Codeforces Round #184 (Div. 2) D、E

来源:互联网 发布:java sql 批处理 编辑:程序博客网 时间:2024/03/29 14:04

        D题根据题目描述,图中只能存在两类边:第一类,对于所有的 i (1<=i<n) 都存在边  i-->i+1;第二类,对于 i  可以存在边 i-->i+k+1 (i>=1 && i+k+1<=n),若边 x-->x+k+1 存在,则不能存在这样的边 y-->y+k+1 (y>=x+k+1)。弄清楚这些后,剩下的就是常规的排列组合了。代码如下(比较挫):

#include<stdio.h>#include<iostream>using namespace std;#define MOD 1000000007bool Is[1000010];long long quickpow(long long i,long long x);long long run(long long L,long long R,long long K);int main(){    int n,m,k,l,r,L,R;    bool flag=true;    long long ans;    l=r=0;    scanf("%d%d%d",&n,&m,&k);    for(int i=0;i<m;i++)    {        int u,v;        scanf("%d%d",&u,&v);        if(flag && v!=u+1)        {            if(v-u-k!=1)            {                flag=false;                continue;            }            Is[u]=true;            if(l==0)                l=r=u;            else                r=u;        }    }    if(flag==false)    {        printf("0\n");        return 0;    }    if(l==0)    {        if(n-(k+1)*2>=0)        {            ans=quickpow(k,2);            ans=((ans*2)%MOD+((n-(k+1)*2)*ans)%MOD)%MOD;            printf("%lld\n",ans);        }        else            if(n-k-1>=0)            {                ans=quickpow(n-k-1,2);                printf("%lld\n",ans);            }            else                printf("1\n");        return 0;    }    if(r-l>k)        printf("0\n");    else    {        L=max(r-k,1),R=min(l+k,n-k-1);        ans=run(L,R,k);        printf("%lld\n",ans);    }    return 0;}long long run(long long L,long long R,long long K){    long long rt,cnt;    cnt=0;    for(int i=L;i<=L+K && i<=R;i++)        if(Is[i]==false)            cnt++;    rt=quickpow(cnt,2);    for(int i=L+1;i<=R-K;i++)    {        if(Is[i-1]==false)            cnt--;        if(Is[i+K]==false)        {            rt=(rt+quickpow(cnt,2))%MOD;            cnt++;        }    }    return rt;}long long quickpow(long long i,long long x){    if(i==0)        return 1;    if(i==1)        return x;    if(i==2)        return x*x;    long long rt=quickpow(i/2,x);    if(i%2==0)        rt=(rt*rt)%MOD;    else        rt=((rt*rt)%MOD*x)%MOD;    return rt;}


       E题,首先找出字符串中所有回文子串的中心,将对应位置的字母替换为 1 ,其余字母替换为 0 。 比如 abacaba 对应的01串为 0101010 。那么问题就转化为:两人轮流取 1 ,最后不能取者,败。取 1 的规则如下:每次至少取1个,如果取走的位置的左右有 1 则也同时取走。被0相互分割的 1 是相互独立的。这显然是一个无偏博弈,用SG函数就可以解决了。

#include<stdio.h>#include<iostream>#include<string.h>using namespace std;#define MAXN 5010int SG[MAXN],F[MAXN],len,ans;char str[MAXN];void Init();bool check(int n);int main(){    scanf("%s",str);    len=strlen(str);    Init();    for(int i=1;i<len-1;)    {        if(str[i-1]==str[i+1])        {            int num=1;            for(int j=i+1;j<len-1;j++)                if(str[j-1]!=str[j+1])                    break;                else                    num++;            ans^=SG[num];            i+=num;        }        else            i++;    }    if(ans==0)        printf("Second\n");    else    {        for(int i=1;i<len-1;i++)            if(str[i-1]==str[i+1] && check(i))            {                printf("First\n%d\n",i+1);                break;            }    }    return 0;}void Init(){    for(int i=1;i<=len;i++)    {        for(int j=1;j<=(i+1)/2;j++)        {            F[SG[max(j-2,0)]^SG[max(i-j-1,0)]]=i;        }        while(F[SG[i]]==i)            SG[i]++;    }}bool check(int n){    int rt,i,l,r;    rt=ans;    l=r=0;    for(i=n-1;i>0;i--)        if(str[i-1]==str[i+1])            l++;        else            break;    for(i=n+1;i<len-1;i++)        if(str[i-1]==str[i+1])            r++;        else            break;    rt=rt^SG[1+l+r]^SG[max(l-1,0)]^SG[max(r-1,0)];    return rt==0;}


原创粉丝点击