2017 ACM-ICPC EC-Final 一些题解

A - Chat Group
水题,意思是求 ∑ i = k n ( n k ) \sum_{i=k}^{n} {n \choose k} i=kn(kn) ,n<1e9,k<1e5。要取模
发现直接按照n来求不行,如果按照k来求的话,我们可以反着做。
发现从 ( n k ) n \choose k (kn) ( n k + 1 ) n \choose k+1 (k+1n) 相当于乘以一个分子n-k,除以一个分母k。这个很简单,推一下就行。

#include 
#define ll long long
using namespace std;
const ll mod = 1e9 + 7;
ll pow_mod(ll a,ll n,ll mod)
{
    ll res = 1;
    a %= mod;
    while(n)
    {
        if(n & 1) res = res * a% mod;
        a = a *a % mod;
        n >>= 1;
    }
    return res;
}

int main()
{
    int ca,cat = 1;
    cin>>ca;
    while(ca--)
    {
        ll n,k;
        cin>>n>>k;
        ll num = n;
        ll ans = pow_mod(2,n,mod)-1;
        for(int i = 1;i<k;i++)
        {
            ans = (ans - num + mod) % mod;
            num = (num*(n - i)%mod)*pow_mod(i+1,mod-2,mod)%mod;
        }
        cout<<"Case #"<<cat++<<": "<<ans<<endl;
    }
}

C - Traffic Light
阅读理解题,也就是说我可以让所有的灯都变成绿的,但是为了给自己找麻烦,需要等一个最长的红灯。
求个max没了,阅读理解题真的没意思

#include 
#define ll long long
using namespace std;
const int MAXN = 2e5 + 5;
int a[MAXN],b[MAXN];
int s[MAXN];
ll sum[MAXN];
int main()
{
    int ca,cat = 1;
    scanf("%d",&ca);
    while(ca--)
    {
        int n;
        scanf("%d",&n);
        for(int i = 1;i<=n+1;i++) scanf("%d",&s[i]),sum[i]=sum[i-1]+s[i];
        for(int i = 1;i<=n;i++) scanf("%d%d",&a[i],&b[i]);
        ll ans = 0;
        for(int i = 1;i<=n;i++)
        {
           ans = max(ans,1LL*b[i]);
        }
        printf("Case #%d: %I64d.000000\n",cat++,sum[n+1] + ans);
    }
}

J - Straight Master
判断一个序列能不能用3,4,5长度的线段,完全覆盖。
找肯定是GG,由线段覆盖我们可以想到差分,差分之后,我们会发现:
如果一个点的值是正的,那么这个点一定有若干个线段是起始点
如果一个点的值是负的,那么这个点一定有若干个线段在这里结尾
顺着这个方向思考,我们会发现一个正数点右边一定有足够的负数点,所以我们直接判断一下这个端点+3位置的点,实际上是长度为3的结束点,假设这里没有长度为3的线段,那么就先保存起来。最后一定会消除,如果不能消除,就说明不能覆盖。

#include 
#define ll long long
using namespace std;
const int MAXN = 2e5 + 5;
int a[MAXN],b[MAXN];
int s[MAXN];
ll sum[MAXN];
int main()
{
    int ca,cat = 1;
    scanf("%d",&ca);
    while(ca--)
    {
        int n;
        scanf("%d",&n);
        for(int i = 1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        for(int i = 1;i<=n;i++)
        {
            b[i] = a[i]-a[i-1];
        }
        b[n+1] = -a[n];
        bool flag = 1;
        if(b[2] <0 || b[3] < 0) flag = 0;
        int sum = 0;
        for(int i = 1;i<=n;i++)
        {
            if(b[i] > 0) sum += b[i];
            if(i +3 > n+1) break;
            if(b[i+3] < 0) sum += b[i+3];
            if(sum < 0) break;
        }
        if(sum != 0)   flag = 0;
        printf("Case #%d: %s\n",cat++,(flag ? "Yes" : "No"));
    }
}

K - Downgrade
阅读理解题,相当于是升级,一个等级i需要Li经验,现在告诉原始的等级,进行N次操作,每次操作把等级当作经验,原来的经验不管,按照升级规则升级,问最后会到多少。
直接模拟就行,阅读理解题真的烦,还是说我有阅读障碍……

#include 
#define ll long long
using namespace std;
const int maxn = 1e5 + 5;
ll a[maxn],sum[maxn];
int main()
{
    int ca,cat = 1;
    scanf("%d",&ca);
    while(ca--)
    {
        int A,B,n;
        scanf("%d%d%d",&A,&B,&n);
        for(int i = 1;i<=A;i++)
        {
            scanf("%lld",&a[i]);
            sum[i] = sum[i-1] + a[i];
        }
        int nowa = A,nowb = B;
        for(int i = 0;i<n;i++)
        {
            int now = lower_bound(sum+1,sum+A+1,nowa) - (sum+1);
            int newa = now+1;
            int newb = nowa - sum[now];
            //cout<
            if(newa == nowa && newb == nowb) break;
            nowa = newa,nowb = newb;
        }
        printf("Case #%d: %d-%d\n",cat++,nowa,nowb);
    }
}

Gym - 101775L
是个找规律,但是有点麻烦。只推了点:
思考必胜态:S _ _ S ,只要能够造出来这个就行了,所以先手可以必胜的N是7=3+1+3,只要S放在中间点
剩下的之后再推吧。

#include 
#define ll long long
using namespace std;
const int MAXN = 2e5 + 5;
int a[MAXN],b[MAXN];
int s[MAXN];
ll sum[MAXN];
int main()
{
    int ca,cat = 1;
    scanf("%d",&ca);
    while(ca--)
    {
        int n;
        scanf("%d",&n);

        printf("Case #%d: ",cat++);
        if(n & 1 && n > 6)
        {
            printf("Panda\n");
        }
        else if( n < 16)
        {
            printf("Draw\n");
        }
        else printf("Sheep\n");

    }
}

M - World Cup
真正的水题,模拟一下就行了

你可能感兴趣的:(ACM,Contest)