比赛链接
https://codeforces.com/contest/1036
A. Function Height
题目大意
个点, 次操作,每次可以使一个点+1,求最终 个点的最大值。
题解
答案就是
B. Diagonal Walking v.2
题目大意
次询问,每次要从 走到 ,一个点可以走多次(包括起点和终点),一个点可以走一步到达周围的8个方向,如果是斜着走的一步就叫做“好的移动”,求 恰好走 步能不能 到达,如果不能输出-1,否则输出最多可以走多少次“好的移动”。
题解
-1的情况很好判断,就是max(n,m)>k
。
否则,如果 与 不同奇偶,必须移动不好的一步来达到同奇偶,剩下的可以全部走斜的。
如果不能恰好走到,也就是 与 不同奇偶,那么必须做两次不好的移动使得恰好能走到 。
C. Classy Numbers
题目大意
次询问,求区间 中有多少个非零数位 的数字。
题解
(伪)数位DP。对于区间 ,拆成 , , ,每段分别统计答案,每段的答案是很好统计的。
D. Vasya and Arrays
题目大意
有一种操作,将序列的任意一段用它们的和代替。现有两个序列 ,可以执行任意次操作,问两个序列最终能否相同,若能,输出两个序列相同时最长的长度,不能输出-1。
题解
如果两个序列的和不同输出-1。
用两个值维护两个序列的前缀和,一个值大了就往另一个值加数,如果两个值相等答案+1。
E. Covered Points
题目大意
条线段,每条线段从 到 ,求至少被一条线段覆盖的整点个数。保证线段两两不在一条直线上。
题解
如果线段没有交点,那么每条线段对答案的贡献就是 。
如果没有3条线段共用一个交点,那么枚举每条线段的交点,如果是整点答案-1。
如果没有上面这些限制,我们可以开一个set,存每条线段与前面线段的交点,最后答案-set的大小。
F. Relatively Prime Powers
题目大意
一个数可以表示成 ,如果 ,就说这个数是好数。 组询问,求 范围内的好数个数。
题解
显然,
范围内好数个数为
但是如果直接这样算是 。
考虑离线算法,按照询问降序排列。
对于每个询问,当 时, 很容易在 时间内得到,而 时, 的值不超过 ,开一个数组记录 ,可以对于每个询问依次减到实际值。 可以预处理 。
总的时间复杂度大概是 。
G. Sources and Sinks
题目大意
将没有入度的点称为源,将没有出度的点称为汇,一个点可以既是源又是汇。给一个 个点 条边的图,保证源和汇的个数相同且都 。现有一个算法:
- 找一个源和一个汇,可以相同。
- 连一条边从汇到源,如果这个图还有源和汇,进入1。
对于这个图,如果在1过程中,无论如何选取源和汇,最后得到的图都是强连通的,输出YES
,否则输出NO
。
题解
设源和汇的个数都为 。
如果一个源集合
能够到达的所有汇为
,对于任意
,若
,那么应该输出NO
,因为如果
中每个点都与
中的点连边,那么
中的点就不能到达非
中的汇点。
现在我们用数学归纳法证明如果对于每个
,都有
或
,那么应该输出YES
。
任取一个点 。
- 一定能走到 (显然)。
- 若 能走到的汇的集合为 ,如果 ,那么证明了强连通;
- 否则,记 能走到的源为 , 能走到的汇为 ,由于 ,因此每一次 的值都在变大,最终变成 。
因此只要 的检查源的集合就可以判断了。
代码
A. Function Height
#include <cstdio>
long long a,b;
int main()
{
scanf("%I64d%I64d",&a,&b);
printf("%I64d\n",(b+a-1)/a);
return 0;
}
B. Diagonal Walking v.2
#include <cstdio>
#include <algorithm>
int q;
long long n,m,k;
int main()
{
scanf("%d",&q);
while(q--)
{
scanf("%I64d%I64d%I64d",&n,&m,&k);
if(n<m)
{
std::swap(n,m);
}
if(k<n)
{
puts("-1");
continue;
}
if((n-m)&1)
{
--k;
}
else if((k-n)&1)
{
k-=2;
}
printf("%I64d\n",k);
}
return 0;
}
C. Classy Numbers
#include <cstdio>
const int pow[]={1,9,81,729};
int C(int a,int b)
{
if(b>a)
{
return 0;
}
int res=1;
for(int i=1; i<=b; ++i)
{
res=res*(a-i+1)/i;
}
return res;
}
int getval(long long x)
{
int have=3,ans=0;
long long bit=1;
for(int i=1; i<=18; ++i)
{
bit*=10;
}
for(int i=18; i>=0; --i)
{
int v=x/bit;
x%=bit;
bit/=10;
if(v==0)
{
continue;
}
for(int j=0; j<have; ++j)
{
ans+=v*C(i,j)*pow[j];
}
ans+=C(i,have)*pow[have];
--have;
if(have<0)
{
break;
}
}
if(have>=0)
{
++ans;
}
return ans;
}
int t;
long long a,b;
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%I64d%I64d",&a,&b);
printf("%d\n",getval(b)-getval(a-1));
}
return 0;
}
D. Vasya and Arrays
#include <cstdio>
int read()
{
int x=0,f=1;
char ch=getchar();
while((ch<'0')||(ch>'9'))
{
if(ch=='-')
{
f=-f;
}
ch=getchar();
}
while((ch>='0')&&(ch<='9'))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
const int maxn=300000;
int n,m,a[maxn+10],b[maxn+10],ans;
long long suma,sumb;
int main()
{
n=read();
for(int i=1; i<=n; ++i)
{
a[i]=read();
suma+=a[i];
}
m=read();
for(int i=1; i<=m; ++i)
{
b[i]=read();
sumb+=b[i];
}
if(suma!=sumb)
{
puts("-1");
return 0;
}
suma=sumb=0;
int l=1,r=1;
while((l<=n)||(r<=m))
{
if(suma<=sumb)
{
suma+=a[l++];
}
else
{
sumb+=b[r++];
}
if(suma==sumb)
{
++ans;
}
}
printf("%d\n",ans);
return 0;
}
E. Covered Points
#include <set>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <algorithm>
int read()
{
int x=0,f=1;
char ch=getchar();
while((ch<'0')||(ch>'9'))
{
if(ch=='-')
{
f=-f;
}
ch=getchar();
}
while((ch>='0')&&(ch<='9'))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
typedef std::pair<int,int> pii;
const int maxn=1000;
const double eps=0.00000001;
struct point
{
double x,y;
point(double _x=0,double _y=0):x(_x),y(_y){}
};
struct seg
{
point l,r;
seg(point _l=0,point _r=0):l(_l),r(_r){}
};
int n,ans;
seg s[maxn+10];
std::set<pii> t;
point getcp(seg a,seg b)
{
double x1=a.l.x-a.r.x,x2=b.l.x-b.r.x,y1=a.l.y-a.r.y,y2=b.l.y-b.r.y;
double bot=y1*x2-x1*y2;
point ans(((b.r.y-a.r.y)*(x1*x2)+a.r.x*(y1*x2)-b.r.x*(x1*y2))/bot,
((a.r.x-b.r.x)*(y1*y2)+b.r.y*(y1*x2)-a.r.y*(x1*y2))/bot);
return ans;
}
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
int tr(double x)
{
if(x>=0)
{
return (int)(x+0.5);
}
else
{
return (int)(x-0.5);
}
}
int main()
{
n=read();
for(int i=1; i<=n; ++i)
{
int lx=read(),ly=read(),rx=read(),ry=read();
s[i]=seg(point(lx,ly),point(rx,ry));
int dx=abs(rx-lx),dy=abs(ry-ly);
ans+=gcd(dx,dy)+1;
t.clear();
for(int j=1; j<i; ++j)
{
point cp=getcp(s[i],s[j]);
int cpx=tr(cp.x),cpy=tr(cp.y);
if((std::abs(cpx-cp.x)<eps)&&(std::abs(cpy-cp.y)<eps)
&&(cpx>=std::min(lx,rx))&&(cpx>=std::min(s[j].l.x,s[j].r.x))
&&(cpx<=std::max(lx,rx))&&(cpx<=std::max(s[j].l.x,s[j].r.x))
&&(cpy>=std::min(ly,ry))&&(cpy>=std::min(s[j].l.y,s[j].r.y))
&&(cpy<=std::max(ly,ry))&&(cpy<=std::max(s[j].l.y,s[j].r.y)))
{
t.insert(std::make_pair(cpx,cpy));
}
}
ans-=t.size();
}
printf("%d\n",ans);
return 0;
}
F. Relatively Prime Powers
#include <cmath>
#include <cstdio>
#include <algorithm>
const int maxk=65;
const int maxn=100000;
const double eps=0.000001;
const long long maxv=1000000000000000000ll;
struct query
{
int id;
long long val;
bool operator <(const query &other) const
{
return val>other.val;
}
};
int p[maxk+10],prime[maxk+10],mu[maxk+10],cnt,end[maxk+10],t;
long long ans[maxn+10];
query q[maxn+10];
int getmu()
{
p[1]=1;
mu[1]=1;
for(int i=1; i<=maxk; ++i)
{
if(!p[i])
{
prime[++cnt]=i;
mu[i]=-1;
}
for(int j=1; (j<=cnt)&&(i*prime[j]<=maxk); ++j)
{
p[i*prime[j]]=1;
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
mu[i*prime[j]]=-mu[i];
}
}
return 0;
}
long long spow(long long x,int b)
{
long long res=1;
while(b)
{
if(b&1)
{
res=res*x;
}
x=x*x;
b>>=1;
}
return res;
}
long long check(long long x)
{
end[2]=sqrt(x);
for(int i=3; i<=maxk; ++i)
{
while(spow(end[i],i)>x)
{
--end[i];
}
}
long long res=x-1;
for(int i=2; i<=maxk; ++i)
{
res+=mu[i]*(end[i]-1);
}
return res;
}
int main()
{
getmu();
for(int i=3; i<=maxk; ++i)
{
end[i]=(long long)(pow(maxv,1.0/i)+eps);
}
scanf("%d",&t);
for(int i=1; i<=t; ++i)
{
scanf("%I64d",&q[i].val);
q[i].id=i;
}
std::sort(q+1,q+t+1);
for(int i=1; i<=t; ++i)
{
ans[q[i].id]=check(q[i].val);
}
for(int i=1; i<=t; ++i)
{
printf("%I64d\n",ans[i]);
}
return 0;
}
G. Sources and Sinks
#include <cstdio>
int read()
{
int x=0,f=1;
char ch=getchar();
while((ch<'0')||(ch>'9'))
{
if(ch=='-')
{
f=-f;
}
ch=getchar();
}
while((ch>='0')&&(ch<='9'))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
const int maxn=1000000;
const int maxk=20;
int source[maxk+3],id[maxn+3],n,m,cnts,cntt;
int ru[maxn+10],chu[maxn+10],to[maxk+3];
int pre[maxn+10],now[maxn+10],son[maxn+10],tot;
int ins(int a,int b)
{
pre[++tot]=now[a];
now[a]=tot;
son[tot]=b;
return 0;
}
int search(int u,int st)
{
if(id[u])
{
to[st]|=1<<(id[u]-1);
}
int j=now[u];
while(j)
{
int v=son[j];
search(v,st);
j=pre[j];
}
return 0;
}
int main()
{
n=read();
m=read();
for(int i=1; i<=m; ++i)
{
int a=read(),b=read();
ins(a,b);
++chu[a];
++ru[b];
}
for(int i=1; i<=n; ++i)
{
if(!ru[i])
{
source[++cnts]=i;
}
if(!chu[i])
{
id[i]=++cntt;
}
}
for(int i=1; i<=cnts; ++i)
{
search(source[i],i);
}
int flag=0;
for(int sta=1; sta<(1<<cnts)-1; ++sta)
{
int ttot=0,scnt=0,cnt=0;
for(int i=1; i<=cnts; ++i)
{
if(sta&(1<<(i-1)))
{
++scnt;
ttot|=to[i];
}
}
for(int i=1; i<=cnts; ++i)
{
if(ttot&(1<<(i-1)))
{
++cnt;
}
}
if(cnt<=scnt)
{
flag=1;
break;
}
}
puts(flag?"NO":"YES");
return 0;
}