FallDream打的AB都FFT了,只剩一个我打的C,没进前一百,之后看看马拉松复活赛有没机会呗。
A. Voltage Keepsake
题目大意:n个东西,每个东西一开始有bi能源,每秒消耗ai能源,每秒可以给一个东西加p能源,秒可以为实数,问至多多少秒内所有东西能源一直为正。(n<=100,000)
思路:二分答案,随便check一下。不特判无解可能会炸精度。
#include<cstdio> #include<algorithm> using namespace std; #define lb long double inline int read() { int x;char c; while((c=getchar())<'0'||c>'9'); for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0'; return x; } #define MN 100000 int a[MN+5],b[MN+5]; int main() { int n=read(),p=read(),t,i;long long cnt=0; lb l,r,mid,sum; for(i=1;i<=n;++i)cnt+=a[i]=read(),b[i]=read(); if(cnt<=p)return 0*puts("-1"); for(t=100,l=0,r=1e12;--t;) { mid=(l+r)/2; for(i=1,sum=0;i<=n;++i)sum+=max((lb)0,a[i]*mid-b[i]); (sum>p*mid?r:l)=mid; } printf("%.10lf",(double)l); }
B. Volatile Kite
题目大意:给出一个n的点的凸多边形,求一个最大的d,使得每个点任意移动d以内的距离,得到的新多边形边不相撞且仍是凸多边形。(n<=1,000)
思路:枚举相邻三个点,d不会超过点i+1到点i与点i+2连线距离的一半,复杂度O(n)。
#include<cstdio> #include<cmath> #include<algorithm> using namespace std; inline int read() { int x,f=1;char c; while((c=getchar())<'0'||c>'9')if(c=='-')f=0; for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0'; return f?x:-x; } #define MN 1000 struct point{double x,y;}p[MN+5]; double dis(point a){return sqrt(a.x*a.x+a.y*a.y);} point operator-(point a,point b){return (point){a.x-b.x,a.y-b.y};} double operator*(point a,point b){return a.x*b.y-a.y*b.x;} int main() { int n=read(),i,j;double ans=1e18; for(i=0;i<n;++i)p[i].x=read(),p[i].y=read(); p[n]=p[0];p[n+1]=p[1]; for(i=0;i<n;++i)ans=min(ans,fabs((p[i+1]-p[i])*(p[i+2]-p[i]))/dis(p[i]-p[i+2])); printf("%.10lf",ans/2); }
C. Vulnerable Kerbals
题目大意:给出m和n个0~m-1内的数,构造一个尽可能长的所有元素都在0~m-1内的数列,使所有前缀积模m不相同且不在n个数中出现过。(0<=n<m<=200,000)
思路:若前i个数的前缀积为x,前i+1个数的前缀积可以为y当且仅当ax-bm=y有解,即gcd(x,m)|y,若我们让所有满足这个条件的x,y,x向y连边,题目即求最长链,gcd(x,m)相同的x在一个连通块内,每个连通块gcd(xi,m)向连通块gcd(xj,m)(gcd(xi,m)|gcd(xj,m))连边,得到一个边数为O(nlogn)的拓扑图,直接DP即可。
#include<cstdio> #include<vector> #include<algorithm> using namespace std; #define ll long long char B[1<<26],*S=B,C;int X; inline int read() { while((C=*S++)<'0'||C>'9'); for(X=C-'0';(C=*S++)>='0'&&C<='9';)X=(X<<3)+(X<<1)+C-'0'; return X; } #define MN 200000 int gcd(int x,int y){return y?gcd(y,x%y):x;} vector<int> v[MN+5]; int m,u[MN+5],f[MN+5],r[MN+5],ls=1; void exgcd(ll x,ll y,ll z,ll&a,ll&b) { if(!y){a=z/x;b=0;return;} ll aa,bb;exgcd(y,x%y,z,aa,bb); a=-bb;b=-aa-bb*(x/y); } void out(int x) { if(!x)return; out(r[x]); int i;ll a,b; for(i=0;i<v[x].size();++i) exgcd(ls,m,v[x][i],a,b), printf("%d ",(a%m+m)%m),ls=v[x][i]; } int main() { fread(B,1,1<<26,stdin); int n,i,j,mx=0; n=read();m=read(); for(i=1;i<=n;++i)u[read()]=1; for(i=1;i<m;++i)if(!u[i])v[gcd(i,m)].push_back(i); for(i=1;i<m;++i) { if((f[i]+=v[i].size())>f[mx])mx=i; for(j=i;j<m;j+=i)if(f[i]>f[j])f[j]=f[i],r[j]=i; } printf("%d ",f[mx]+!u[0]); out(mx); if(!u[0])puts("0"); }
D. Varying Kibibits
题目大意:给出n个数的集合T,F(S)的各位数字为集合S中各个数字对应位数字的最小值,例如F(123,321)=121,求的异或和。(n<=10^6,数字<=999,999)
思路:F值恰好为x的子集不好求,我们考虑求出F值各位数字都大等x的子集,也就是数字各位都大等于x的数的集合的所有子集,答案我们枚举各位加一,容斥一下即可求出,现在问题是如何求出这个集合的子集和的平方和,只要同时维护一个集合的子集和的和、子集和的平方和、集合大小,就可以支持合并集合和删除集合(稍微推一下式子,挺简单的,或者看下面的代码),数字各位都大等于x的集合同样也可以容斥求出,总复杂度O(2^6*n),可能需要卡卡常数,正解貌似是O(6n)的,以后补。
#include<cstdio> char B[1<<26],*S=B,C;int X; inline int read() { while((C=*S++)<'0'||C>'9'); for(X=C-'0';(C=*S++)>='0'&&C<='9';)X=X*10+C-'0'; return X; } #define MN 1000000 #define MOD 1000000007 int a[MN+5],p2[MN+5],r2[MN+5],pw[7]; struct data { int s1,s2,sz; data(int s1=0,int s2=0,int sz=0):s1(s1),s2(s2),sz(sz){} void operator+=(const data&b) { s2=(1LL*s2*p2[b.sz]+1LL*b.s2*p2[sz]+2LL*s1*b.s1)%MOD; s1=(1LL*s1*p2[b.sz]+1LL*b.s1*p2[sz])%MOD; sz+=b.sz; } void operator-=(const data&b) { sz-=b.sz; s1=((s1-1LL*b.s1*p2[sz])%MOD+MOD)*r2[b.sz]%MOD; s2=((s2-2LL*s1*b.s1-1LL*b.s2*p2[sz])%MOD+MOD)*r2[b.sz]%MOD; } }s[MN+5]; void solve1(int x,int k,int d,int p) { if(d>5){if(x!=k)if(p>0)s[x]+=s[k];else s[x]-=s[k];return;} solve1(x,k,d+1,p); if(k%pw[d+1]/pw[d]<9)solve1(x,k+pw[d],d+1,-p); } inline int mod(int x){if(x>=MOD)x-=MOD;if(x<0)x+=MOD;return x;} void solve2(int x,int k,int d,int p) { if(d>5){if(x!=k)s[x].s2=mod(s[x].s2+p*s[k].s2);return;} solve2(x,k,d+1,p); if(k%pw[d+1]/pw[d]<9)solve2(x,k+pw[d],d+1,-p); } int main() { B[fread(B,1,1<<26,stdin)]=0; int n=read(),i;long long ans=0; while(n--)++a[read()]; for(p2[0]=i=1;i<=MN;++i)p2[i]=(p2[i-1]<<1)%MOD; for(r2[0]=i=1;i<=MN;++i)r2[i]=(r2[i-1]*((MOD+1LL)>>1))%MOD; for(pw[0]=i=1;i<7;++i)pw[i]=pw[i-1]*10; for(i=MN;i--;){solve1(i,i,0,-1);while(a[i]--)s[i]+=data(i,1LL*i*i%MOD,1);} for(i=1;i<MN;++i)solve2(i,i,0,1),ans^=1LL*i*s[i].s2; printf("%I64d",ans); }