bzoj 3598: [Scoi2014]方伯伯的商場之旅【數位dp】
阿新 • • 發佈:2018-09-10
scan clu cpp ems turn htm main ostream spa
參考了這個http://www.cnblogs.com/Artanis/p/3751644.html,好像比一般方法好寫
大概思想就是先計算出把所有石子都合並到1位置的代價,這樣顯然有一些是不優的,然後再分別計算把合並到1的石子合並到p,能優化多少
這個計算就是枚舉2到tot位,對於每一位計算挪到這位能被優化的數最多能被優化多少,因為合並點右移的代價是sum[w]-(sum[n]-sum[w]),所以只要這個為負數就退出即可
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=1005; long long l,r,k,f[N][2],sm[N][2],g[N][N],a[N],tot; long long dp(int w,int lm) { if(w==0) { sm[w][lm]=1; return 0; } if(f[w][lm]) return f[w][lm]; long long r=0,s=0; for(int i=0;i<=(lm?a[w]:k-1);i++) { r+=dp(w-1,lm&&(i==a[w]))+i*(w-1)*sm[w-1][lm&&(i==a[w])]; s+=sm[w-1][lm&&(i==a[w])]; } sm[w][lm]=s; return f[w][lm]=r; } long long wk(long long x) { memset(f,0,sizeof(f)); tot=0; while(x) a[++tot]=x%k,x/=k; return dp(tot,1); } long long dfs(int w,int lm,int p,int s) { if(w==0) return s; if(!lm&&g[w][s]) return g[w][s]; long long r=0; for(int i=0;i<=(lm?a[w]:k-1);i++) { long long nw=(w>=p?1:-1)*i+s; if(nw<0) break; r+=dfs(w-1,lm&&i==a[w],p,nw); } if(lm) return r; return g[w][s]=r; } long long clc(long long x) { tot=0; while(x) a[++tot]=x%k,x/=k; long long r=0; for(int i=2;i<=tot;i++) { memset(g,0,sizeof(g)); r+=dfs(tot,1,i,0); } return r; } int main() { scanf("%lld%lld%lld",&l,&r,&k); printf("%lld\n",wk(r)-wk(l-1)-(clc(r)-clc(l-1))); return 0; }
bzoj 3598: [Scoi2014]方伯伯的商場之旅【數位dp】