cf 831C - Jury Marks 【二分】


点击打开链接


这题题意对我来说不太好理解。。


题意: 

            一个人参加节目,然后有k个评委依次给他打了k次分。

            每个人初始有个初始分,但是这个人他忘了,他只能记得n次某个评委给他打过后的总得分是多少,

           现在问你这个人的初始分合法的个数有多少个。


题解:

         刚开始是在读不懂,猜了个题意写了一发, wa到了text 10;

         我看我答案少了2情况,然后发现前缀和数组需要去重。

         去完重tle到test 11.。。。。。。。


         首先评委打分是有次序的,所以求出前缀和。

         之前做法其实就是枚举每个他记得的值减去其前缀和得到一个初始值,然后如果一个初始值能出现n次,那么此值可行。

         我tle 但是在最后根本没有必要的sort之后,竟然1300+ms给过了。代码如下,谁要是知道这个sort快到哪了还望指出。。。 

         

#include<bits/stdc++.h>
#define ll long long
#define mod 1000000007
using namespace std;
const int maxn=2020;
const int inf=1<<29;
int a[maxn],x;
int sum[maxn];
map<int,int>ma;
vector<int>vec;
int n,m,cnt=0;
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;++i){
        scanf("%d",&a[i]);
        sum[i]=sum[i-1]+a[i];
    }
    sort(sum+1,sum+1+n);
    int cnt=unique(sum+1,sum+n+1)-(sum+1);
    int ans=0;
    for(int i=1;i<=m;++i){
        scanf("%d",&x);
        for(int j=1;j<=cnt;++j){
            vec.push_back(x-sum[j]);
        }
    }
    sort(vec.begin(),vec.end());//就这个神奇的sort
    for(int i=0;i<vec.size();++i) ma[vec[i]]++;
    for(int i=0;i<vec.size();++i){
        if(ma[vec[i]]>=m){
            ans++;
            ma[vec[i]]=0;
        }
    }
    printf("%d",ans);
    return 0;
}

         由于苦思不能理解这个神奇的sort 我就想这肯定不是最正确的方法,就不管了开始想怎么解决。

        后来看到大佬代码,用的二分,瞬间就有思路了。。。。。。(哎,无奈自己没想到)

        二分的话,先把前缀和sum排序,

        然后记得的评分a也要排序,之后枚举需要a[j]-a[i](j>i)如果不排序会出错。wa到test 7.。。。。。

        首先要明白,所有答案最多只有评委的数量个(因为要满足一个初始值满足所有情况,那么答案一定是a[1]-sum[i]中的一个)

        现在我们就要二分验证每个a[i]-(a[1]-sum[i])是否在sum之中存在,若不存在,则不合法。

       a[i]-(a[1]-sum[i])其实就是 前缀和中有没有一个能使a[1]-sum[i] ->a[i];


#include<bits/stdc++.h>
const int maxn=2020;
using namespace std;
int n,m,l,r,cnt,ans=0,x;
int a[maxn],sum[maxn];
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;++i){
        scanf("%d",&x);
        sum[i]=sum[i-1]+x;
    }
    sort(sum+1,sum+n+1);
    cnt=unique(sum+1,sum+n+1)-(sum+1);
    for(int i=1;i<=m;++i)
        scanf("%d",&a[i]);
    sort(a+1,a+m+1);
    for(int i=1;i<=cnt;++i){
        int num=a[1]-sum[i];
        int f=1;
        for(int j=2;j<=m;++j){
            int pos=upper_bound(sum+1,sum+cnt+1,a[j]-num)-(sum+1);
            //printf("%d~~~%d\n",sum[pos],a[j]-num);
            if(sum[pos]!=a[j]-num){
                f=0;
                break;
            }
        }
        if(f) ans++;

    }
    printf("%d",ans);
    return 0;
}


        

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值