P3286 [SCOI2014] Uncle Fang's shopping mall tour problem solution

This question is a digital DP with an unusual routine.

First of all, according to the knowledge of elementary school Mathematical Olympiad, we can know that it is the best to merge all the stones in the middle. However, this is useless, and we don't know what is in the middle.

Then we first think about a question: suppose the current merge point is tag tagt a g , when we update the merge point totag + 1 tag+1tag+At 1 , marktag + 1 tag+1tag+An answer has toanstag + 1 ans_ {tag + 1a n stag+1, The first answer is ans 1 ans_1a n s1,那么: a n s t a g + 1 − a n s 1 ans_{tag+1}-ans_1 a n stag+1a n s1 Is it monotonic?

The answer is: yes.

why? When we continue to move the merge point to the right, obviously more points will go to the left. At this time, there will be more and more stones on the left, resulting in more and more impacts for every square move, so it is monotonic.

Then we have a way of thinking: first calculate the answer that is merged into point 1, and then greedily move it to the right, and the answer will become smaller if it gets smaller.

So this question is finished

It has not been done so far because the code cannot be written.

The special thing about this question is that we have to write two dfs.

  1. LL dfs1(int pos, int sum, int limit)
    s u m sum s u m represents the contribution that has been calculated.
  2. LL dfs2(int pos, int sum, int tag, int limit)
    t a g tag t a g is the new merging point.
    In thedfs2middle, we need to calculate the contribution of the new left minus right of the contribution of the difference, the equivalent for Prefix and thought, if calculated is positive, then update the answer.

It's done here.

Code note:

  1. Empty ff at any timef array.
  2. Note that the upper limit of digits is k − 1 k-1k1

Code:

#include <bits/stdc++.h>
#define Max(a, b) ((a > b) ? a : b)
using namespace std;

typedef long long LL;
const int MAXN = 1e5 + 10;
LL l, r, f[70][MAXN];
int k, cnt, a[70];

LL read()
{
    
    
	LL sum = 0, fh = 1; char ch = getchar();
	for (; ch < '0' || ch > '9'; ch = getchar()) fh -= (ch == '-') << 1;
	for (; ch >= '0' && ch <= '9'; ch = getchar()) sum = (sum << 3) + (sum << 1) + (ch ^ 48);
	return (fh == 1) ? sum : -sum;
}

LL dfs1(int pos, int sum, int limit)
{
    
    
	if (pos == 0) return sum;
	if (!limit && f[pos][sum] != -1) return f[pos][sum];
	int t = limit ? a[pos] : k - 1; LL ans = 0;
	for (int i = 0; i <= t; ++i) ans += dfs1(pos - 1, sum + i * (pos - 1), limit && i == a[pos]);
	if (!limit) f[pos][sum] = ans;
	return ans;
}

LL dfs2(int pos, int sum, int tag, int limit)
{
    
    
	if (sum < 0) return 0;
	if (pos == 0) return sum;
	if (!limit && f[pos][sum] != -1) return f[pos][sum];
	int t = limit ? a[pos] : k - 1; LL ans = 0;
	for (int i = 0; i <= t; ++i) ans += dfs2(pos - 1, sum + ((pos < tag) ? -i : i), tag, limit && i == a[pos]);
	if (!limit) f[pos][sum] = ans;
	return ans;
}

LL Get(LL p)
{
    
    
	memset(f, -1, sizeof(f)); cnt = 0;
	for (; p; p /= k) a[++cnt] = p % k;
	LL sum = dfs1(cnt, 0, 1);
	for (int i = 2; i <= cnt; ++i)
	{
    
    
		memset(f, -1, sizeof(f));
		sum -= dfs2(cnt, 0, i, 1);
	}
	return sum;
}

int main()
{
    
    
	l = read(), r = read(), k = read();
	printf ("%lld\n", Get(r) - Get(l - 1));
	return 0;
}

Guess you like

Origin blog.csdn.net/BWzhuzehao/article/details/114545554