VK Cup 2017

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);
}
原文地址:https://www.cnblogs.com/ditoly/p/VK-Cup-2017-R2.html