【HDU4869】Turn the pokers-思維
阿新 • • 發佈:2018-12-13
測試地址:Turn the pokers 題目大意: 有張牌,一開始正面都朝下,有次操作,每次操作給出一個,表示要從這些牌中選出張翻面,求所有操作完成後能得到多少種不同的正/反面序列。 做法: 本題需要用到思維。 因為將牌做任何置換都是合法的,因此只要我們能構造出最後有張正面的情況,就會對答案有的貢獻,因此問題就變成求哪些可以得到。 這裡有一個結論:如果的最小值是,最大值是,那麼在區間中所有與和關於同餘的數都是合法的。這個東西如果一下子無法理解,可以使用數學歸納的思想。假設某一次操作前滿足這個性質,我們只要證明經過一次操作後還是滿足這個性質即可。具體的證明各種分類討論比較麻煩,但感性理解還是可以的。因此我們只要求和即可。 我們假設已經求出第次操作前的,那麼: 如果,那麼; 否則如果,那麼; 否則,如果和關於同餘,,否則。 這樣的分類討論應該還是不難理解的,就是能把正面翻過去就把正面翻過去,這樣正面的數量就最小。 而的討論相似,只不過是能翻反面翻反面。這樣我們就解決了這一題。 以下是本人程式碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1000000009;
int n,m;
ll fac[100010],inv[100010],invfac[100010];
ll C(ll n,ll m)
{
return fac[n]*invfac[m]%mod*invfac[n-m]%mod;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
fac[0]=fac[1]=inv[1]=invfac[0]=invfac[1]=1;
for (ll i=2;i<=m;i++)
{
fac[i]=fac[i-1]*i%mod;
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
invfac[i]=invfac[i-1]*inv[i]%mod;
}
int L=0,R=0;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
int nxtL,nxtR;
if (x<=L) nxtL=L-x;
else if (x>=R) nxtL=x-R;
else nxtL=(x-L)%2;
if (x<=m-R) nxtR=R+x;
else if (x>=m-L) nxtR=2*m-L-x;
else nxtR=m-((x-m+R)%2);
L=nxtL,R=nxtR;
}
ll ans=0;
for(int i=L;i<=R;i+=2)
ans=(ans+C(m,i))%mod;
printf("%lld\n",ans);
}
return 0;
}