UVALive 7505 Hungry Game of Ants ACM/ICPC ECFinal 2015(dp+思维)

来源:互联网 发布:如何测试端口通不通 编辑:程序博客网 时间:2024/05/16 10:09




        大致思路都想得差不多了,但是最后几步还是想错了点……

        大致题意:有n只蚂蚁排成一条线质量为1~n,每只蚂蚁要么往左走要么往右走,如果两只蚂蚁相遇质量大的会把小的给吃了,而且之后质量叠加。当蚂蚁走到头之后就掉头,然后质量相同的时候,左边把右边吃掉。最后只会剩下一只蚂蚁,现在问第k只蚂蚁想要成为最后一只蚂蚁,有多少种方案。

        很容易想到,对于1~k只蚂蚁,只有一些关键的蚂蚁是有限制的。显然,任何一只蚂蚁除了第n只,往右走一定会被其右边的蚂蚁吃掉。所以第k只一定要往左走。又由于它要一直存活,所以他左边的蚂蚁合起来不能比它的质量高。因此我们要找到一个最大的i,i<=k,使得s[i-1]<s[k]-s[i-1],其中s[i]为1~n的前缀和。这样我把i~k的蚂蚁都合成到第k只蚂蚁身上,它的总质量大于1~i只蚂蚁的和,那么前面的蚂蚁就可以任意方向走,方案数就是2^(i-1)。

        现在我们来看后面的部分。我们用dp[i]表示前k只蚂蚁合并之后,再合上第k+1~i只蚂蚁后,且第i只蚂蚁往左走的方案数。因为只有i往左边走,i才有可能与左边的合并。又为了保证第k只蚂蚁能够存活到最后,要有条件s[p]>s[i]-s[p],表示前p个蚂蚁必须先合并,保证第k只存活。而这里i是不断变大的,所以说这里满足条件的p也是单调增加的。有转移方程dp[i]=2*dp[i-1]-dp[p](s[p]>s[i]-s[p]),即第i-1个蚂蚁不一定要往左故乘以2,然后前p个必须先合并,故减去前p-1合并的方案数且第p~i-1只蚂蚁都往右的方案数。还是说的不清楚,不理解的就提问吧。真的不好说……具体见代码:

#include<bits/stdc++.h>#define mod 1000000007#define LL long long#define N 1000010using namespace std;LL n,k,t,dp[N];LL s(LL x){    return x*(x+1)/2;}LL s(LL l,LL r){    return s(r)-s(l-1);}LL qpow(LL a,LL b)//qpow{    LL res=1;    while(b)    {        if (b&1) res=res*a%mod;        b>>=1; a=a*a%mod;    }    return res;}int main(){    int T_T,T=0;    cin>>T_T;    while(T_T--)    {        t=1;        scanf("%lld%lld",&n,&k);        if (k==1) {printf("Case #%d: 0\n",++T);continue;}        LL now=k,p; for(p=k-1;now<=s(p);p--)now+=p,t++;        dp[k]=dp[k+1]=qpow(2LL,p); p=k;        for(int i=k+2;i<=n;i++)        {            dp[i]=2*dp[i-1]%mod;            while(p<i&&s(p)<s(p+1,i)) dp[i]=((dp[i]-dp[p++])%mod+mod)%mod;        }        printf("Case #%d: %lld\n",++T,dp[n]*2LL%mod);    }    return 0;}

阅读全文
0 0
原创粉丝点击