Codeforces Round #519

我收回我之前说的可能不会更新了,迫切需要整理思路

思维现在真的是完全没有…了呢,写模拟题都fst。

之前其实没怎么打过CF,今天一打开想起自己还是?名(?介于蓝绿色间的那个),太惨了8,泪目。呜呜呜呜呜呜

A. Elections

题意:有n个学生,每人有k张选票。如果一个人给Elodreip投a[i]票,Awruk将得到k-a[i]票。问最小的k使得Awruk赢得选举。

用sum记录a[i]总和,k*n-sum>sum即赢得选举的条件。为了避免奇奇怪怪的问题出现,我选择直接枚举

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define Max(a,b) (a>b?a:b)
using namespace std;
int main()
{
    int n,sum=0,maxn=0,a;
    scanf("%d",&n); 
    for(int i=1;i<=n;i++)
    scanf("%d",&a),sum+=a,maxn=Max(maxn,a);
    for(int i=maxn;;i++)
    {
        if(i*n-sum>sum){printf("%d\n",i);break;}
    }
    return 0;
} 
B. Lost Array
题意:a[0]=0,a[i]=x[(i-1)%k]+a[i-1],给定长度为n的数组,推出可能的x数组的所有长度k(1<=k<=n)
先对数组a差分求得x[(i-1)%k]。枚举可能的长度,如该长度可行,x[(i-1)%k]将以该长度为循环节周期性重复
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<algorithm>
#define Max(a,b) (a>b?a:b)
using namespace std;
vector<int>v;
int a[1005],n,ans=0;
int main()
{
    scanf("%d",&n),a[0]=0;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=n;i;i--)a[i]-=a[i-1];
    for(int i=1;i<=n;i++)
    {
        bool f=1;
        for(int j=1;;j++)
        {
            if(j+i>n)break;
            if(a[j]!=a[j+i]){f=0;break;}
        }
        if(f)v.push_back(i);
    }
    printf("%d\n",v.size());
    for(int i=0;i<v.size();i++)
    printf("%d ",v[i]);
    return 0;
} 
C. Smallest Word
题意:给出一个由'a''b'组成的长度小于1000的字符串,从前到后每一位i,你可以决定要不要把[1,i]位字符串反转。求如何能得到字典序最小的字符串。
发现开vp的时候读错题了,我死了。
字符串仅含有'a''b',通过操作得到的最终结果必然是若干个a在前,若干个b在后。
前面的操作里我们只需要把所有的a和b分别凑在一起,到最后一位反转/不反转确保a在前b在后。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define Min(a,b) (a<b?a:b)
#define MAXN 300003
#define Max(a,b) (a>b?a:b)
#define LL long long 
using namespace std;
char s[1002];
int main()
{
    scanf("%s",s+1);
    int len=strlen(s+1);
    for(int i=1;i<len;i++)
    {
        if(s[i+1]==s[i])printf("0 ");
        else printf("1 "),swap(s[1],s[i]);
    }
    if(s[len]=='a')printf("1\n");
    else printf("0\n");
    return 0;
} 
D. Mysterious Crime

题意:共有m个长度为n的字符串,现在可对每个字符串进行操作去掉它的前缀和后缀,使得所有字符串剩余部分相同,问有多少种方案

问题可以看做求所有字符串的公共子串的个数,我们知道如果一个字符串s在每个字符串里都出现,那这个子串的任意子串也都符合题意,这个字符串对ans的贡献是(1+|s|)*|s|/2

由于每个字符串都是1到n的排列,我们可以预处理出每个数字后的一个数字是否相同,辅助我们算出所有不能再拓展的串s,说到这里相信你已经能脑补出来了,具体实现还是看代码。

nxt[i][j]:第i个串数字j的下一个数字 f[i]:所有串中数字i的下一个数字(若下一位不相同则为-1) len[i]:以数字i开始的串最多可以拓展几位

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define Min(a,b) (a<b?a:b)
#define N 100002
#define M 12
#define Max(a,b) (a>b?a:b)
#define LL long long 
using namespace std;
int n,m,a[M][N],nxt[M][N],f[N],len[N];
LL ans=0;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&a[i][j]);
            if(j-1)nxt[i][a[i][j-1]]=a[i][j];
            if(j==m)nxt[i][a[i][j]]=-1;
        }
    }
    for(int i=1;i<=n;i++)
    {
        int same=nxt[1][i];
        for(int j=2;j<=m;j++)
        if(nxt[j][i]!=same){same=-1;break;}
        f[i]=same;
    }
    for(int i=n;i;i--)
    {
        int num=a[1][i];
        len[num]=1;
        if(f[num]!=-1)len[num]+=len[f[num]];
    }
    for(int i=1;i<=n;i+=len[a[1][i]])
    {
        int l=len[a[1][i]];
        ans+=(1LL+l)*l/2;
    }
    printf("%I64d\n",ans);
    return 0;
} 
E. Train Hard, Win Easy

题意:共有n个参赛者,给出xi,yi分别为每个人参加第一场比赛与第二场比赛的得分。共有m组敌对关系,有敌对关系的人不会配合参加比赛。现在教练需要让所有没有敌对关系的人配合参加比赛(其中一人负责第一场,另一人第二场),最终得分越小越好。求每个人的得分

可以想到先统计所有人两两配合的最小分数,再减去有敌对关系组的分数。

两个人i,j比赛应使得分数为min{xi+yj,xj+yi}

xi+yj<xj+yi即xi-yi<xj-yj,故可以对xi-yi排序,则i的得分为xi*排在i后面的数个数+yi*排在i前面的数个数

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define Min(a,b) (a<b?a:b)
#define MAXN 300003
#define Max(a,b) (a>b?a:b)
#define LL long long 
using namespace std;
LL read()
{
    LL 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*10+c-'0';c=getchar();}
    return x*f;
}
LL A[MAXN],B[MAXN];
struct Node{LL a,b,num;}p[MAXN];
LL presa[MAXN],presb[MAXN];
bool operator < (const Node x,const Node y)
{
    return x.a-x.b<y.a-y.b;
}
LL ans[MAXN];
int main()
{
    int n=read(),m=read();
    for(int i=1;i<=n;i++)
    A[i]=p[i].a=read(),B[i]=p[i].b=read(),p[i].num=i;
    sort(p+1,p+1+n);
    presa[0]=0,presb[0]=0;
    for(int i=1;i<=n;i++)
    presa[i]=presa[i-1]+p[i].a,presb[i]=presb[i-1]+p[i].b;
    
    for(int i=1;i<=n;i++)
    {
        ans[p[i].num]=p[i].a*(n-i)+p[i].b*(i-1);
        ans[p[i].num]+=presb[n]-presb[i];
        ans[p[i].num]+=presa[i-1];
    }
    
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        ans[x]-=Min(A[x]+B[y],A[y]+B[x]);
        ans[y]-=Min(A[x]+B[y],A[y]+B[x]);
    }
    for(int i=1;i<=n;i++)printf("%I64d ",ans[i]);
    return 0;
} 

 

转载于:https://www.cnblogs.com/Zars19/p/9939679.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值