1. 程式人生 > >BZOJ3598 SCOI2014方伯伯的商場之旅(數位dp)

BZOJ3598 SCOI2014方伯伯的商場之旅(數位dp)

一個數 bzoj3 根據 clu long long stream 由於 bsp div

  看到數據範圍就可以猜到數位dp了。顯然對於一個數最後移到的位置應該是其中位數。於是考慮枚舉移到的位置,那麽設其左邊和為l,左右邊和為r,該位置數為p,則需要滿足l+p>=r且r+p>=l。同時為了防止重復,枚舉的應該是最左的能移到的位置,那麽還需要滿足l<p+r。算的時候枚舉p、l、r,統計方案數,對於已固定部分直接計入,剩余部分由於每個位置都是相同的,根據距離平均值算出代價。註意討論各種情況,非常惡心。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include
<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<0||c>9) {if (c==-) f=-1;c=getchar();} while (c>=0&&c<=9) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define ll long long #define
N 66 #define K 22 ll l,r; int k,n,a[N]; ll f[N][N*K]; ll solve(ll m) { ll s=0; n=-1; while (m) a[++n]=m%k,m/=k; for (int i=n;~i;i--) { for (int y=0;y<a[i];y++) { for (int j=n;j>i;j--) { int l=0,r=0,t=0; for (int
x=n;x>j;x--) l+=a[x],t+=a[x]*(x-j); for (int x=j-1;x>i;x--) r+=a[x],t+=a[x]*(j-x); r+=y;t+=y*(j-i);t<<=1; for (int v=max(r,l-a[j]+1);a[j]>=v-l&&v-r<=i*(k-1);v++) s+=f[i][v-r]*(t+(v-r)*(j-i+1+j)); } int l=0,t=0; for (int x=n;x>i;x--) l+=a[x],t+=a[x]*(x-i); t<<=1; for (int v=max(0,l-y+1);y>=v-l&&v<=i*(k-1);v++) s+=f[i][v]*(t+v*(1+i)); for (int j=i-1;~j;j--) { int t=0,u=0; for (int x=n;x>i;x--) u+=a[x],t+=a[x]*(x-j); u+=y,t+=y*(i-j);t<<=1; for (int p=0;p<k;p++) { for (int l=0;l<=(i-j-1)*(k-1);l++) for (int v=max(0,l+u-p+1);p>=v-l-u&&v<=j*(k-1);v++) s+=f[j][v]*f[i-j-1][l]*(t+l*(i-j)+v*(1+j)); } } } } return s>>1; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj3598.in","r",stdin); freopen("bzoj3598.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif cin>>l>>r>>k; f[0][0]=1; for (int i=0;i<60;i++) for (int j=0;j<=i*(k-1);j++) if (f[i][j]&&f[i][j]<1E16) for (int x=0;x<k;x++) f[i+1][j+x]+=f[i][j]; cout<<solve(r+1)-solve(l); return 0; }

BZOJ3598 SCOI2014方伯伯的商場之旅(數位dp)