题意: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; }