标签:style blog http os io for ar 代码
题意:给你n张牌,一开始都是背面朝下的,现在有一些操作,每次操作都可以随意改变s[i]张牌的状态,问最后的牌有多少种状态。
标程题解:
最终的结果一定是连续出现的,只需要求出最终的区间。
因为如果对同一张牌进行两次操作,牌的状态不改变。故牌的翻转次数一定是减少偶数次。如果所有数的和是奇数,那么最终结果也一定是奇数。同理,偶数也是一样的。
所以只要递推求出最后的区间,计算sum(C(xi,m)(i=0,1,2。。。)),m是总牌数,xi是在区间内连续的奇数或偶数,在模10^9+9就是最终的答案。
根据它的思路,可以求出一个区间,就是最后还有多少张牌朝上的一个区间,这个区间要么是连续的偶数,要么是连续的奇数。
求出区间,还需要用到一个费马小定理+快速幂 解决C(m,k) %mod
C(m,k)=m!/(k!*(m-k)!) 对C(m,k)取模mod
取模运算规则:
在求 m!/(k!*(m-k)!)的时候由于有除法不能像以上那样一步取模一次,因此我们想到了用费马小定理把分母转化成整数再用第三条求模。
费马小定理:假如a是整数,p是质数,且a,p互质,那么a的(p-1)次方除以p的余数恒等于1。
那么a^(p-1)/a = 1/a%p 得到1/a%p= a^(p-2) , 将一个分数的值化成了整数
因此在求以上令a=k!*(m-k)! , p=mod(即mod=1000000009),
1/(k!*(m-k)!) %mod= (k!*(m-k)!)^(mod-2)
于是这个题目可以ac了......
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
typedef __int64 ss;
const ss inf=100005;
const ss mod=1000000009;
ss s[inf],n,m;
ss f[inf];
ss deal(ss x,ss y)
{
if(y==1)
return x;
if(y%2==0)
{
ss sum=deal(x,y/2)%mod;
return (sum*sum)%mod;
}
else
{
ss sum=deal(x,y/2)%mod;
return sum*sum%mod*x%mod;
}
}
int main()
{
f[0]=1;
f[1]=1;
for(ss i=2;i<=inf-4;i++)
f[i]=f[i-1]*i%mod;
while(scanf("%I64d%I64d",&n,&m)>0)
{
ss minx=0,maxn=0;
ss p,p1;
for(ss i=0;i<n;i++)
{
scanf("%I64d",&s[i]);
}
minx=0;
maxn=0;
for(ss i=0;i<n;i++)
{
if(minx>=s[i]) p=minx-s[i];
else if(s[i]<=maxn)
{
if(maxn%2==s[i]%2)
p=0;
else p=1;
}
else p=s[i]-maxn;
if(maxn+s[i]<=m) p1=maxn+s[i];
else if(minx+s[i]<=m)
{
if(m%2==(minx+s[i])%2)
p1=m;
else p1=m-1;
}
else p1=2*m-(minx+s[i]);
minx=p;
maxn=p1;
}
//printf("%I64d %I64d\n",minx,maxn);
ss sum=0;
for(ss i=minx;i<=maxn;i+=2)
{
sum+=((f[m]%mod)*(deal((f[i]*f[m-i])%mod,mod-2)%mod))%mod;
sum%=mod;
}
printf("%I64d\n",sum%mod);
}
return 0;
}
标签:style blog http os io for ar 代码
原文地址:http://www.cnblogs.com/ziyi--caolu/p/3888546.html