Educational Codeforces Round 50
1036A - Function Height 20180907
\(ans=\left \lceil \frac{k}{n} \right \rceil\)
#include<bits/stdc++.h> using namespace std; #define LL long long LL n,k; int main() { scanf("%I64d%I64d",&n,&k); printf("%I64d\n",(k-1)/n+1); return 0; }
1036B - Diagonal Walking v.2 20180907
简单分类讨论即可
#include<bits/stdc++.h> using namespace std; #define N 10001 #define LL long long LL q,n,m,k; int main() { scanf("%I64d",&q); while(q--) { scanf("%I64d%I64d%I64d",&n,&m,&k); if(max(n,m)>k){printf("-1\n");continue;} printf("%I64d\n",n+m&1?k-1:(k+m&1?k-2:k)); } }
1036C - Classy Numbers 20180907
暴力预处理出所有满足条件的数,排序后去重即可
#include<bits/stdc++.h> using namespace std; #define LL long long LL T,l,r,cnt,p[18],f[19260817]; int main() { p[0]=1,f[++cnt]=1000000000000000000ll; for(LL i=1;i<18;i++)p[i]=p[i-1]*10ll; for(LL i=1;i<=999;i++) { LL x=i/100,y=(i/10)%10,z=i%10; for(LL a=0;a<18;a++) for(LL b=0;b<18;b++)if(b!=a) for(LL c=0;c<18;c++)if(c!=b && c!=a) f[++cnt]=x*p[a]+y*p[b]+z*p[c]; } sort(f+1,f+cnt+1); cnt=unique(f+1,f+cnt+1)-f-1; scanf("%I64d",&T); while(T--) { scanf("%I64d%I64d",&l,&r); printf("%I64d\n",(LL)(upper_bound(f+1,f+cnt+1,r)-lower_bound(f+1,f+cnt+1,l))); } }
1036D - Vasya and Arrays 20180907
预处理两个数组的前缀和,当且仅当\(a_n=b_m\)时有解,答案就是\(a_i=b_j\)的方案数
#include<bits/stdc++.h> using namespace std; #define N 300005 #define LL long long LL n,m,a[N],b[N],ans; int main() { scanf("%I64d",&n); for(LL i=1;i<=n;i++) scanf("%I64d",&a[i]),a[i]+=a[i-1]; scanf("%I64d",&m); for(LL i=1;i<=m;i++) scanf("%I64d",&b[i]),b[i]+=b[i-1]; if(a[n]!=b[m])return printf("-1\n"),0; LL i=1,j=1; while(i<=n && j<=m) { while(a[i]<b[j] && i<=n)i++; while(b[j]<a[i] && j<=m)j++; if(i<=n && j<=m && a[i]==b[j]) i++,ans++; } printf("%I64d\n",ans); return 0; }
1036E - Covered Points 20180907
首先,若设一个线段对应的向量是(x,y),则这个线段上的整点数量为gcd(x,y)+1,之后考虑把相交的整点部分去除就好了
注意判断交点是否为整点时,不建议直接强转成整型,否则可能会有精度损失(比如可能会将2记录为1.99999999,强制转换后会变为1)
前方超长代码预警,学长的模板真是太好用了xD
#include<bits/stdc++.h> using namespace std; typedef long double lod; typedef long long ll; typedef long double ld; const ld eps=1e-8; const ld pi=acos(-1.0); int sgn(ld x) { if (x<-eps) return -1; if (x>eps) return 1; return 0; } struct P; //点,向量 struct LINE; //线段,射线,直线; struct CIRCLE; struct TRIANGLE; struct POLYGON; void kr(ld &x) { double t; scanf("%lf",&t); x=t; } void kr(ll &x) { scanf("%I64d",&x); } struct P { lod x,y; void read() { kr(x); kr(y); } P operator+(const P &t)const { return {x+t.x,y+t.y}; } P operator-(const P &t)const { return {x-t.x,y-t.y}; } P operator*(ld t)const { return {x*t,y*t}; } P operator/(ld t)const { return {x/t,y/t}; } lod operator*(const P &t)const { return x*t.y-y*t.x; } //叉积 lod operator%(const P &t)const { return x*t.x+y*t.y; } //点积 bool operator<(const P &t)const { return sgn(x-t.x)<0||sgn(x-t.x)==0&&sgn(y-t.y)<0; } bool operator==(const P &t)const { return sgn(x-t.x)==0&&sgn(y-t.y)==0; } ld ang()const { return atan2(y,x); } ld length()const { return sqrt(x*x+y*y); } P rotate(const P &t,ld sita)const { return {(x-t.x)*cos(sita)-(y-t.y)*sin(sita)+t.x, (x-t.x)*sin(sita)+(y-t.y)*cos(sita)+t.y}; } //逆时针转sita ld btang(const P &t)const { return acos( (*this%t)/length()/t.length() ); } //向量夹角 P midvec(const P &t)const { return (*this)/length()+t/t.length(); } //角平分向量 }; struct LINE { P p1,p2; void read() { p1.read(); p2.read(); } LINE midLINE() { P midp=(p1+p2)/2; P v=p2-p1; v=v.rotate({0,0},pi/2); return {midp,midp+v}; } //中垂线 bool have1(const P &p)const { return sgn( (p-p1)*(p-p2) )==0&&sgn( (p-p1)%(p-p2) )<=0; } //线段上有点 bool have2(const P &p)const { return sgn( (p-p1)*(p-p2) )==0&&sgn( (p-p1)%(p2-p1) )>=0; } //射线上有点 bool have3(const P &p)const { return sgn( (p-p1)*(p-p2) )==0; } //直线上有点 lod areawith(const P &p)const { return abs( (p1-p)*(p2-p)/2 ); } //线段和点围成面积 P vecfrom(const P &p)const { P v=(p2-p1); v=v.rotate({0,0},pi/2); ld s1=(p1-p)*(p2-p); ld s2=v*(p2-p1); v=v*(s1/s2); return v; }//点到直线垂足的向量 P footfrom(const P &p)const { P v=vecfrom(p); return p+v; } //点到直线垂足 ld dis1from(const P &p)const { P foot=footfrom(p); if (have1(foot)) return (foot-p).length(); return min( (p1-p).length(),(p2-p).length()); }//点到线段距离 ld dis2from(const P &p)const { P foot=footfrom(p); if (have2(foot)) return (foot-p).length(); return (p1-p).length(); }//点到射线距离 ld dis3from(const P &p)const { return vecfrom(p).length(); }//点到直线距离 P symP(const P &p)const { P v=vecfrom(p); return p+v*2; } //点关于直线的对称点 //1线段 2射线 3直线 bool isct11(const LINE &L)const { P a1=p1,a2=p2; P b1=L.p1,b2=L.p2; if (sgn( max(a1.x,a2.x)-min(b1.x,b2.x) )<0|| sgn( max(b1.x,b2.x)-min(a1.x,a2.x) )<0|| sgn( max(a1.y,a2.y)-min(b1.y,b2.y) )<0|| sgn( max(b1.y,b2.y)-min(a1.y,a2.y) )<0) return 0; lod tmp1=(a2-a1)*(b1-a1); lod tmp2=(a2-a1)*(b2-a1); if (sgn(tmp1)<0&&sgn(tmp2)<0||sgn(tmp1)>0&&sgn(tmp2)>0) return 0; tmp1=(b2-b1)*(a1-b1); tmp2=(b2-b1)*(a2-b1); if (sgn(tmp1)<0&&sgn(tmp2)<0||sgn(tmp1)>0&&sgn(tmp2)>0) return 0; return 1; } //前提是不重合且有交点,p1沿p2-p1方向到达L上的长度,负数表示反向 //直线交多边形需要用到 ld dis33(const LINE &L)const { return (L.p1-p1)*(L.p2-p1) / ( (p2-p1)*(L.p2-L.p1) ) * (p2-p1).length(); } P isctPoint(const LINE &L)const { ld len=dis33(L); P v=p2-p1; return p1+v*(len/v.length()); } }; ll n,x,y,z,w,ans; LINE a[1001]; map<pair<ll,ll>,set<ll> >f; ll gcd(ll x,ll y){return y?gcd(y,x%y):x;} bool check(lod k){return fabs(k-round(k))<eps;} #define mp make_pair int main() { kr(n); for(ll i=1;i<=n;i++) { kr(x),kr(y),kr(z),kr(w); ll dx=abs(z-x),dy=abs(w-y); ans+=gcd(dx,dy)+1; a[i]={{(lod)x,(lod)y},{(lod)z,(lod)w}}; } for(ll i=1;i<=n;i++) for(ll j=i+1;j<=n;j++) if(a[i].isct11(a[j])) { P p=a[i].isctPoint(a[j]); if(check(p.x) && check(p.y)) f[mp(round(p.x),round(p.y))].insert(i), f[mp(round(p.x),round(p.y))].insert(j); } for(auto x:f)ans-=(ll)x.second.size()-1; printf("%I64d\n",ans); return 0; }
1036F - Relatively Prime Powers 20180907
考虑预处理不满足条件的数,设\(k_i\)的gcd值为K,显然当一个数x对应的K>1时,有\(x=m^{K}\),这里m为大于1的整数。因此我们可以发现其实不满足条件的数就是满足\(x=m^{K}\)的数\(x\)的集合,其中m,K均为大于1的整数。由于n的范围是1e18,所以可以暴力预处理K>2的情况,并把可以表示为平方数的数暂时去掉,之后排序再去重一下就好了。
代码中的Sqrt是为了防止精读误差写的,以前被坑过 于是后来较大的数开方就都这么写了_(:з」∠)_
#include<bits/stdc++.h> using namespace std; #define LL long long LL T,n,cnt,f[2000001]; LL Sqrt(LL k) { LL x=sqrt(k); while(x*x<k)x++; while(x*x>k)x--; return x; } bool check(LL k) { LL x=Sqrt(k); return x*x<k; } int main() { LL N=1000000000000000000ll; for(LL i=2;i<=1000000;i++) { LL b=i*i; while(b<=N/i) { b*=i; if(check(b)) f[++cnt]=b; } } sort(f+1,f+cnt+1); cnt=unique(f+1,f+cnt+1)-f-1; scanf("%I64d",&T); while(T--)scanf("%I64d",&n),printf("%I64d\n",n-(LL)(upper_bound(f+1,f+cnt+1,n)-f-1)-Sqrt(n)); return 0; }
1036G - Sources and Sinks 20180908
显然原图联通等价于由源点和汇点组成的图联通,考虑源点的集合X,X中源点能到达的汇点的集合为Y,可以发现若|Y|<=|X|,则答案一定是NO。遍历所有源点的子集(空集和全集)即可
#include<bits/stdc++.h> using namespace std; #define N 1000001 int n,m,u,v,k,I[N],O[N]; vector<int>d[N],t; bool x[21][N]; set<int>s; void dfs(int k,int cur) { x[k][cur]=true; for(auto nxt:d[cur]) if(!x[k][nxt])dfs(k,nxt); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d",&u,&v), d[u].push_back(v), I[v]++,O[u]++; for(int i=1;i<=n;i++) { if(!I[i])dfs(k++,i); if(!O[i])t.push_back(i); } for(int i=1;i<(1<<k)-1;i++) { s.clear(); int cnt=0; for(int j=0;j<k;j++) if(i&(1<<j)) { cnt++; for(auto nxt:t) if(x[j][nxt])s.insert(nxt); } if(s.size()<=cnt)return printf("NO\n"),0; } return printf("YES\n"),0; }