abcdeffa's Blog

当局者迷,旁观者清。

0%

GMOJ S3848 【大水题】

Description

给你一个 $n ^ 2$ 位的数 $k$ ,请你求出有多少个整数 $x \in [1, k]$ ,满足 $x$ 翻转或大于 $k$ 或翻转后大于等于它自己。 例如 123 翻转后为 321

Solution

对于这类问题,我们考虑使用 数位 DP 来解决。

正难则反,考虑求出翻转后小于等于 $k$ , 小于 它自己的数的个数。

所以如果设 $f(i)$ 表示 $i$ 翻转后的结果,那么答案 $ans=$

于是我们可以想到设 $f(i, p=0/1, q=0/1)$ 表示当前做到第 $i$ 位, $p$ 表示当前 小于/等于 $k$ 的前 $i$ 位,$q$ 表示将前 $i$ 位翻转后得到的后 $i$ 位 小于等于/大于 $k$ 的后 $i$ 位。

于是我们就得到了一个时间复杂度为 $O(n ^ 2)$ 的做法,具体细节见代码部分。

Code

  • 易懂
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <cstdio>
#define maxN 1000010
#define mod 1000000007
long long f[maxN][2][2], a[maxN];
int main ()
{
long long ans = 0, n = 0;
scanf("%lld", &n);
n *= n;
for(long long i = 1;i <= n; i++)
{
scanf("%1lld", &a[i]);
ans = ans * 10 + a[i];
ans %= mod;
}
f[0][1][0] = 1;
for(long long i = 0;i <= n - 1; i++)
{
for(long long p = 0;p <= 1; p++)
{
for(long long q = 0;q <= 1; q++)
{
for(long long k = 0;k <= 9; k++)
{
if(p && k > a[i + 1])
{
break;
}
long long pp = 0, qq = 0;
if(p)
{
if(k == a[i + 1])
{
pp = 1;
}
}
if(!q)
{
if(k > a[n - i])
{
qq = 1;
}
}
else
{
if(k >= a[n - i])
{
qq = 1;
}
}
f[i + 1][pp][qq] += f[i][p][q];
f[i + 1][pp][qq] %= mod;
}
}
}
}
long long da1 = (f[n][0][0] + f[n][1][0]) % mod;
long long da2 = ((f[n / 2][0][0] + f[n / 2][0][1]) % mod + f[n / 2][1][0]) % mod;
ans = (ans + mod - ((da1 + mod - da2) % mod * 500000004LL % mod)) % mod;
printf("%lld", ans);
return 0;
}
  • 简洁
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <cstdio>
#define maxN 1000010
#define mod 1000000007
long long f[maxN][2][2], a[maxN];
int main ()
{
long long ans = 0, n = 0;
scanf("%lld", &n);
for(long long i = 1;i <= n * n; i++)
{
scanf("%1lld", &a[i]);
(ans = ans * 10 + a[i]) %= mod;
}
f[0][1][0] = 1;
for(long long i = 0;i < n * n; i++)
{
for(long long p = 0;p <= 1; p++)
{
for(long long q = 0;q <= 1; q++)
{
for(long long k = 0;k <= 9; k++)
{
if(!(p & (k > a[i + 1])))
{
(f[i + 1][p & (k == a[i + 1])][((!q) & (k > a[n * n - i])) | (q & (k >= a[n * n - i]))] += f[i][p][q]) %= mod;
}
}
}
}
}
ans = (ans + mod - (((f[n * n][0][0] + f[n * n][1][0]) % mod + mod - ((f[n * n / 2][0][0] + f[n * n / 2][0][1]) % mod + f[n * n / 2][1][0]) % mod) % mod * 500000004LL % mod)) % mod;
printf("%lld", ans);
return 0;
}