传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3598
题意:
对于一个数x,它含有一些小石子,每个石子的值为a[i](a[i]为x在k进制下的第i位),选一个石子的位置pos使得sum(a[i] * abs(i-pos))最小。 求出[L,R]中所有数这个值的和。
题解:
对于一个数,我们枚举最优位置时,可以发现从i->i+1的变化为+pre[i]-suf[i+1](分别为前缀和与后缀和)。
30%的暴力分,我们枚举[L,R]中的数,然后进行上述操作即可。
那么100%的分呢?我们考虑将每一个数的位置设为1,答案为a[i]*(i-1),然后数位dp求出初始花费cost。 对于将位置i->i+1的变化,+前i个数 -后i+1个数。我们考虑枚举这个操作,并且求出进行这一操作后对于这些数共计会优多少。
上面那些看不懂的话来看这里吧_(:з」∠)_。
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <iostream> 5 #define LL long long 6 using namespace std; 7 const int MaxN = 65; 8 int u[MaxN], d[MaxN], LEN; 9 LL l, r, k; 10 LL f[MaxN][2][2], g[MaxN][1600], ans[2333], sum[MaxN][2][2]; 11 12 LL dp(int len, int up, int down){ 13 if (!len) { sum[len][up][down] = 1; return 0; } 14 if (f[len][up][down]!= -1) return f[len][up][down]; 15 LL ret = 0ll, num = 0ll; 16 int top = up ? u[len] : (int)k-1, bot = down ? d[len] : 0; 17 for (int i = bot; i <= top; i++){ 18 int p1 = (i==top)&&up, p2 = i==bot&&down; 19 ret += dp(len-1, p1, p2) + i*(len-1)*sum[len-1][p1][p2]; 20 num += sum[len-1][p1][p2]; 21 } 22 f[len][up][down] = ret, sum[len][up][down] = num; 23 return ret; 24 } 25 26 LL calc(LL x, LL y){ 27 int len = 0, len2 = 0; 28 while(x){ 29 u[++len] = (int) (x%k); 30 x /= k; 31 } 32 while(y){ 33 d[++len2] = (int) (y%k); 34 y /= k; 35 } 36 LEN = len; 37 return dp(len, 1, 1); 38 } 39 40 LL dfs(int len, int up, int down, int p, int s){ 41 if (!len) return (LL)s; 42 if (!up && !down && g[len][s] != -1) return g[len][s]; 43 LL ret = 0; 44 int top = up ? u[len] :(int)k-1, bot = down ? d[len] : 0; 45 for (int i = bot; i <= top; i++){ 46 int x = (len >= p ? 1 : -1), c = i==top&&up, d = i==bot&&down; 47 x = x*i + s; 48 if (x < 0) break; 49 ret += dfs(len-1, c, d, p, x); 50 } 51 if (!up && !down) g[len][s] = ret; 52 return ret; 53 } 54 55 void Solve(){ 56 memset(f, -1ll, sizeof(f)); 57 LL ret = calc(r, l); 58 //cout<<ret<<endl; 59 LL dec = 0ll; 60 for (int i = 2; i <= LEN; i++){ 61 memset(g, -1ll, sizeof(g)), dec += dfs(LEN, 1, 1, i, 0); 62 } 63 cout<<ret - dec; 64 } 65 66 int main(){ 67 cin>>l>>r>>k; 68 Solve(); 69 return 0; 70 }