題意:ios
長度是n的線段上點的編號從1~n,每一個點有一隻螞蟻螞蟻的體重等於該點的編號,最初每隻螞蟻能夠選擇向右走或者向左走兩隻螞蟻相遇時體重大的吃掉體重小的而且體重增長爲兩隻的體重和,走到邊界時掉頭,問第k只螞蟻活到最後的方案數。spa
Limits: • 1 ≤ T ≤ 100. • 1 ≤ K ≤ N. • 2 ≤ N ≤ 106 .code
Sample Inputblog
3string
2 1it
3 2io
4 2class
Sample Outputstream
Case #1: 0im
Case #2: 4
Case #3: 4
代碼:
//k==1而且n!=1時答案是0。 //對於第k只螞蟻若是他要活到最後他必定是開始向左走(最後一隻除外),把左邊的螞蟻都吃掉而後掉頭向右走,在第k只 //螞蟻左邊的螞蟻中最右邊的一隻向左走的螞蟻p必定是會吃掉它左邊的全部螞蟻而後再向右走所以(p+1~k-1)的螞蟻都是 //向右走的而且他們被k吃掉後k的總重量要大於p的總重量。p+1~k方向固定,1~p各有兩個方向能夠選擇。 //而後考慮k右邊的螞蟻,當吃掉第i只螞蟻時的方案數能夠由第i-1只獲得,假設如今左邊k已經吃完第lef只螞蟻了,假 //設第i只螞蟻向左走那麼它被吃掉的方案數就是第i-1只被吃掉的方案數可是還要考慮當lef+1~i-1的螞蟻都向右走而且 //他們加上i的體重大於k的體重了那麼這種方案就不行,這種的方案共有f[lef](f[i]表示第i只螞蟻向左走的方案數)種 //,要減去。假設第i只螞蟻向右走那麼它被吃掉的方案數仍是第i-1只被吃掉的方案數(假設i是最後一隻)。 #include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long ll; const ll MOD=1e9+7; const int MAXN=1000009; int t,k,n,fin[MAXN]; ll tp[MAXN],f[MAXN],ans; int search(int x) { int l=1,r=x,ss; ll aa=1LL*x*(x+1)/2; while(l<=r){ ll mid=(l+r)>>1; ll tmp1=mid*(mid+1)/2; ll tmp2=aa-tmp1; if(tmp2<=tmp1) { ss=mid;r=mid-1; } else l=mid+1; } return ss; } void init() { tp[0]=1; for(int i=1;i<=MAXN-3;i++) tp[i]=(tp[i-1]*2)%MOD; fin[1]=1; for(int i=2;i<=MAXN-3;i++) fin[i]=search(i); } int main() { init(); scanf("%d",&t); for(int cas=1;cas<=t;cas++){ scanf("%d%d",&n,&k); if(k==1&&n!=1) ans=0; else{ f[k]=tp[fin[k]-1]; ll tmp=f[k]; int lef=k; for(int i=k+1;i<=n;i++){ int j=fin[i]; while(lef<j){ tmp=((tmp-f[lef])%MOD+MOD)%MOD; lef++; } f[i]=tmp; tmp=(tmp*2)%MOD; } ans=(f[n]*2)%MOD; } printf("Case #%d: %lld\n",cas,ans); } return 0; }