D

找出在[a,b]之间的,奇数位不为d偶数位为d且为m的倍数的数的个数,a,b有2000位

数位dp
$d_{i,j,k}$ 表示前i位%m余数为j的数的个数,k表示该位是否受限,0不受限,1等于a该位上的数,2等于b该位上的数

复杂度$O(10mn)$

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
63
64
65
66
67
68
69
70
71
72
73
#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
const LL mod = 1e9 + 7;
const int maxn = 2010;
char a[maxn],b[maxn];
int n,m,d;
LL dp[maxn][maxn][3];

LL solve()
{
int i = 0,rem = 0;
while(i < n && a[i] == b[i])
{
int t = a[i] - '0';
if((i&1 && t!=d) || (!(i&1) && t==d)) return 0;
rem = (rem*10 + t)%m;
++i;
}
if(i>=n) return rem == 0;
for(int j=a[i]-'0';j<=b[i]-'0';++j)
{
if((i&1 && j!=d) || (!(i&1) && j==d)) continue;
int r = (rem*10+j)%m;
if(j == a[i]-'0')
++dp[i][r][1];
else if(j == b[i]-'0')
++dp[i][r][2];
else
++dp[i][r][0];
}
++i;
for(;i<n;++i)
{
int L = a[i] - '0',R = b[i] - '0';
for(int j=0;j<m;++j)
{
for(int k=0;k<10;++k)
{
if((i&1 && k!=d) || (!(i&1) && k==d)) continue;
int r = (j*10+k)%m;

dp[i][r][0] = (dp[i][r][0]+dp[i-1][j][0])%mod;
if(k>=L)
{
if(k == L)
dp[i][r][1] = (dp[i][r][1]+dp[i-1][j][1])%mod;
else
dp[i][r][0] = (dp[i][r][0]+dp[i-1][j][1])%mod;
}
if(k <= R)
{
if(k == R)
dp[i][r][2] = (dp[i][r][2]+dp[i-1][j][2])%mod;
else
dp[i][r][0] = (dp[i][r][0]+dp[i-1][j][2])%mod;
}
}
}
}
return (dp[n-1][0][0] + dp[n-1][0][1] + dp[n-1][0][2]) %mod;
}

int main()
{
//freopen("test.txt","r",stdin);
scanf("%d %d",&m,&d);
scanf("%s %s",a,b);
n = strlen(a);
printf("%lld\n",solve());
return 0;
}

E

求图中所有的z的个数

树状数组
预处理出每个点向左和向右的最长延伸,处理每条反对角线(/),用树状数组维护每个位置上的小z的位置
每次查询即在当前可向左下角延伸最大距离的区间(小于等于其向左延伸的距离)内统计z的个数,然后当每个小z超过其可延伸范围时更新树状数组

复杂度$O(mnlog(n+m))$

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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include<bits/stdc++.h>
using namespace std;

typedef long long LL;

const int maxn = 3010;
char s[maxn][maxn];
int L[maxn][maxn],R[maxn][maxn];
int n,m;
vector<int> over[maxn];
int bit[maxn];

int lowbit(int x)
{
return x&-x;
}

int query(int p)
{
++p;
int res = 0;
for(int i=p;i>0;i-=lowbit(i))
res += bit[i];
return res;
}

void add(int p,int val)
{
++p;
for(int i=p;i<maxn;i+=lowbit(i))
bit[i] += val;
}

void init()
{
for(int i=0;i<n;++i)
{
L[i][0] = s[i][0] == 'z';
for(int j=1;j<m;++j)
{
if(s[i][j] == 'z')
L[i][j] = L[i][j-1] + 1;
else
L[i][j] = 0;
}
R[i][m-1] = s[i][m-1] == 'z';
for(int j=m-2;j>=0;--j)
{
if(s[i][j] == 'z')
R[i][j] = R[i][j+1] + 1;
else
R[i][j] = 0;
}
}
}

int main()
{
// freopen("test.txt","r",stdin);
scanf("%d %d",&n,&m);
for(int i=0;i<n;++i) scanf("%s",s[i]);
init();
LL ans = 0;
for(int i=0;i<n;++i)
{
memset(bit,0,sizeof bit);
for(int j=0;j<maxn;++j) over[j].clear();
int x = i,y = 0,lst = -1;
while(x >= 0 && y < m)
{
if(s[x][y] == '.')
lst = y;
else
{
add(y,1);
over[y+R[x][y]-1].push_back(y);
ans += query(y) - query(y - min(L[x][y],y - lst));
}
for(int j=0;j<over[y].size();++j) add(over[y][j],-1);
--x;
++y;
}
}
for(int i=1;i<m;++i)
{
memset(bit,0,sizeof bit);
for(int j=0;j<maxn;++j) over[j].clear();
int x = n-1,y = i,lst = -1;
while(y < m && x >= 0)
{
if(s[x][y] == '.')
lst = y;
else
{
add(y,1);
over[y+R[x][y]-1].push_back(y);
ans += query(y) - query(y - min(L[x][y],y - lst));
}
for(int j=0;j<over[y].size();++j) add(over[y][j],-1);
--x;
++y;
}
}
printf("%lld\n",ans);
return 0;
}