Codeforces Round #519 by Botan Investments翻车记

  A:枚举答案即可。注意答案最大可达201,因为这个wa了一发瞬间爆炸。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 110
int n,a[N],mx;
int main()
{
/*#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
#endif*/
    n=read();
    int tot=0;
    for (int i=1;i<=n;i++) mx=max(mx,a[i]=read()),tot+=a[i];
    for (int i=mx;i<=201;i++)
    {
        int cnt=0;
        for (int j=1;j<=n;j++) cnt+=i-a[j];
        if (cnt>tot) {cout<<i;return 0;}
    }
    return 0;
}
View Code

  B:看了半天题。枚举即可。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 1010
int n,a[N],b[N],cnt=0,c[N];
int main()
{
/*#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
#endif*/
    n=read();
    for (int i=1;i<=n;i++) a[i]=read();
    for (int k=1;k<=n;k++)
    {
        bool flag=1;
        for (int i=1;i<=k;i++) b[i]=a[i]-a[i-1];
        for (int i=k+1;i<=n;i++) if (a[i]-a[i-1]!=b[(i-1)%k+1]) {flag=0;break;}
        if (flag) c[++cnt]=k;
    }
    cout<<cnt<<endl;
    for (int i=1;i<=cnt;i++) cout<<c[i]<<' ';
    return 0;
}
View Code

  C:看了半天题。想了半天。每次都在字符的分界处翻转,就可以得到最优解(即a都在前面b都在后面)。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 1010
int n,a[N];
bool flag[N];
char s[N];
int main()
{
/*#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
#endif*/
    scanf("%s",s+1);
    n=strlen(s+1);
    for (int i=1;i<=n;i++) a[i]=s[i]=='b';
    for (int i=1;i<=n;i++)
    {
        int t=i;
        while (t<n&&a[t+1]==a[i]) t++;
        if (t<n||a[i]==0) reverse(a+i+1,a+t+1),flag[t]=1;
        i=t;
    }
    for (int i=1;i<=n;i++) cout<<flag[i]<<' ';
    return 0;
}
View Code

  D:看了半天题。暴力匹配,如果失配这些数不可能再被计入答案。这样分成了很多段,将每段答案加起来即可。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 100010
#define M 12
int n,m,a[M][N],p[M][N],q[12];
long long ans;
bool check()
{
    for (int i=1;i<=m;i++)
    {
        q[i]++;
        if (q[i]>n) return 0;
    }
    for (int i=2;i<=m;i++)
    if (a[i][q[i]]!=a[i-1][q[i-1]]) return 0;
    return 1;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
#endif
    n=read(),m=read();
    for (int i=1;i<=m;i++)
        for (int j=1;j<=n;j++)
        a[i][j]=read(),p[i][a[i][j]]=j;
    for (int i=1;i<=n;i++)
    {
        int x=i;
        q[1]=i;
        for (int j=2;j<=m;j++) q[j]=p[j][a[1][i]];
        while (x<n&&check()) x++;
        ans+=1ll*(x-i+2)*(x-i+1)/2;
        i=x;
    }
    cout<<ans;
    return 0;
}
View Code

  E:看了半天题。看题时间跟想+码的时间差不多了。首先给出的那些边显然可以直接排除。现在要求的是ansi=Σmin(xi+yj,xj+yi),可以将其变成ansi=Σmin(xi-yi-xj+yj,0)+xj+yi。这样min里面的东西只需要二分查一个前缀和。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 300010
int n,m,t=0;
long long ans[N],b[N],pre[N],sum;
struct data{int x,y;
}a[N];
int main()
{
#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
#endif
    n=read(),m=read();
    for (int i=1;i<=n;i++) sum+=a[i].x=read(),a[i].y=read(),b[i]=a[i].y-a[i].x;
    sort(b+1,b+n+1);
    for (int i=1;i<=n;i++) pre[i]=pre[i-1]+b[i];
    for (int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        ans[x]-=min(a[x].x+a[y].y,a[x].y+a[y].x),ans[y]-=min(a[x].x+a[y].y,a[x].y+a[y].x);
    }
    /*for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
        if (i!=j) ans[i]+=min(a[i].x-a[i].y+b[j],0)+a[i].y+a[j].x;*/
    for (int i=1;i<=n;i++)
    {
        ans[i]+=sum-a[i].x+1ll*a[i].y*(n-1);
        int l=1,r=n,t=0;
        while (l<=r)
        {
            int mid=l+r>>1;
            if (b[mid]+a[i].x-a[i].y<0) t=mid,l=mid+1;
            else r=mid-1;
        }
        ans[i]+=pre[t]+1ll*t*(a[i].x-a[i].y);
    }
    for (int i=1;i<=n;i++) printf("%I64d ",ans[i]);
    return 0;
}
close
View Code

  F:做法似乎很多。比赛时只想到设f[i]为gcd=i时最少选多少元素,考虑通过与i的gcd数量是i的因子个数来优化,预处理可以向哪转移。这一部分看起来可以瞎优化到不错的效率,然而又wa又T最后弃疗了。

  题解给的是状压dp,没有太懂(upd:好像也是算方案数)。似乎也有不少随机化做法。

  感觉最妙的做法还是这样:强化这个题,求选k个数时的方案数。这显然可以莫比乌斯反演,预处理每个数在a中有多少个是其倍数即可,这可以利用调和级数做到log。显然最终答案若存在一定不超过7,于是复杂度O(n+vlogv)。这应该是保证正确性(取模后变成0什么的就算了吧)的最优做法了。把一个判定性问题转化为数数题居然能够简化问题非常有意思。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 300010
#define P 1000000007
int n,a[N],mobius[N],prime[N],tot[N],cnt;
int fac[N],inv[N];
bool flag[N];
int C(int n,int m)
{
    if (m>n) return 0;
    return 1ll*fac[n]*inv[m]%P*inv[n-m]%P;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("f.in","r",stdin);
    freopen("f.out","w",stdout);
#endif
    n=read();
    for (int i=1;i<=n;i++) a[read()]++;
    flag[1]=1;mobius[1]=1;
    for (int i=2;i<=N-10;i++)
    {
        if (!flag[i]) prime[++cnt]=i,mobius[i]=-1;
        for (int j=1;j<=cnt&&prime[j]*i<=N-10;j++)
        {
            flag[prime[j]*i]=1;
            if (i%prime[j]==0) break;
            else mobius[prime[j]*i]=-mobius[i];
        }
    }
    fac[0]=1;for (int i=1;i<=N-10;i++) fac[i]=1ll*fac[i-1]*i%P;
    inv[0]=inv[1]=1;for (int i=2;i<=N-10;i++) inv[i]=P-1ll*(P/i)*inv[P%i]%P;
    for (int i=2;i<=N-10;i++) inv[i]=1ll*inv[i-1]*inv[i]%P;
    for (int i=1;i<=N-10;i++)
        for (int j=i;j<=N-10;j+=i)
        tot[i]+=a[j];
    for (int k=1;k<=7;k++)
    {
        int ans=0;
        for (int i=1;i<=N-10;i++)
        ans=((ans+mobius[i]*C(tot[i],k))%P+P)%P;
        if (ans) {cout<<k;return 0;}
    }
    cout<<-1;
    return 0;
}
View Code

  这场阅读量实在太大,读题感觉花了快有30min。A wa一发掉了至少30名非常惨了。

  result:rank 417 rating -6

   

原文地址:https://www.cnblogs.com/Gloid/p/9868476.html