题意:
长度是n的线段上点的编号从1~n,每个点有一只蚂蚁蚂蚁的体重等于该点的编号,最初每只蚂蚁可以选择向右走或者向左走两只蚂蚁相遇时体重大的吃掉体重小的并且体重增加为两只的体重和,走到边界时掉头,问第k只蚂蚁活到最后的方案数。
Limits: • 1 ≤ T ≤ 100. • 1 ≤ K ≤ N. • 2 ≤ N ≤ 106 .
Sample Input
3
2 1
3 2
4 2
Sample Output
Case #1: 0
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 ",cas,ans); } return 0; }