UVALive 7505 Hungry Game of Ants
阿新 • • 發佈:2018-09-05
star ... turn case sys arr names quic using
1. 筆記
比較容易的動態規劃題。往左很好考慮,往右用dpi表示前i只都被k吃掉後,k繼續往右仍然不死的情況數。狀態轉移方程為dp[I]=dp[I+1]+...+dp[j],分別對應第I+1位向左,...,第j位向左(I和j之間的都向右)。其中j為滿足條件的最大的螞蟻(如果I+1到j都向右,j向左,那麽k死)。貌似這個dp和網上一些題解不太一樣,不過沒細看。這些都不要緊,關鍵的是寫完代碼各自玄學TLE,花了足足五個小時才改到A,最後發現罪魁禍首是sqrt。。。吐血。以前從來沒註意過這個,今天才發現凡是小數運算都奇慢無比,真是血的教訓啊。
2. 代碼
#include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=a;i<=b;++i) #define ms(arr,a) memset(arr,a,sizeof arr) #define debug(x) cout<<"< "#x" = "<<x<<" >"<<endl typedef long long ll; const int maxn=1e6+5; const ll mod=1e9+7; int pos[maxn]; int dp[maxn]; int n,k; int quick_pow(int a,int n) { register int ret=1; while(n) { if(n&1)ret=1LL*ret*a%mod; a=1LL*a*a%mod; n>>=1; } return ret; } inline ll sum(int x) { return 1LL*x*(x+1); } int bs(int l,int r,int i) { int m;bool ll=(sum(l)<=2*sum(i)),rr=(sum(r)<=2*sum(i)); if(ll&&rr)return r; if(!ll&&!rr)return -1; if(!ll){r=r^l;l=r^l;r=r^l;} while(r-l>1||l-r>1) { m=(l+r)/2; if(sum(m)<=2*sum(i))l=m; else r=m; } return l; } int main() { //freopen("Input.txt","r",stdin); //freopen("1.txt","w",stdout); for(int i=1;i<maxn;++i)pos[i]=bs(i+1,maxn,i); int T;scanf("%d",&T); rep(Case,1,T) { scanf("%d%d",&n,&k); if(k==1){printf("Case #%d: 0\n",Case);continue;} dp[n]=1;dp[n+1]=0; for(int i=n-1;i>=k;--i) { int j=pos[i]; j=min(n,j); dp[i]=((2*dp[i+1]-dp[j+1])%mod+mod)%mod; } int l=1,m,r=k-1; while(l<r) { m=(l+r+1)/2; if(2*sum(m)<sum(k))l=m; else r=m-1; } //l=ceil(sqrt(k*(k+1)/2+0.25)-0.5)-1; printf("Case #%d: %lld\n",Case,1LL*quick_pow(2,l+1)*(dp[k]-dp[k+1]+mod)%mod);// } //freopen("CON","w",stdout); //system("start Output.txt"); }
UVALive 7505 Hungry Game of Ants