您的位置:首页 > 其它

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

2013-05-24 08:17 417 查看
        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 1000000007

bool 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 5010

int 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息