赛场上k题写链表的启发式合并,直接给写跪了,耽误了太多时间,导致最后只出了7题,D题dp给漏了,好菜啊…
C.Distinct Substrings
题意:给一个长度为 的字符串 ,定义 为在 串末尾添加字符 新增加的本质不同子串数量,求 的异或和
解法:我们把字符串颠倒一下,问题转化成在 前面添加一个字符,所能增加的本质不同子串数,假设添加了 ,求出 与 所有子串最长的lcp,显然 ,用 求 每个后缀与 的最长公共前缀,用 表示 与 的lcp,如果 ,显然我们可以更新: ,这样,就解决掉这题难点啦
//其实还可以二分+hash,但是我t了,好像有看到别人这么过了
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e6 + 3, mod = 1e9 + 7;
// 字符串下标从0开始
int nex[maxn], ex[maxn]; //模式串nex,匹配串ex
void get_nex(int *str, int len) {
int i = 0, j, pos;
nex[0] = len;
while (str[i] == str[i+1] && i+1 < len) ++i;
nex[1] = i;
pos = 1;
for (int i = 2; i < len; ++i) {
if (nex[i-pos] + i < nex[pos] + pos) nex[i] = nex[i-pos];
else {
j = nex[pos] + pos - i;
if (j < 0) j = 0;
while (i+j < len && str[j] == str[j+i]) ++j;
nex[i] = j;
pos = i;
}
}
}
void get_ex(int *s1, int *s2, int len1, int len2) { // s1匹配s2
int i = 0, j, pos;
get_nex(s2, len2);
while (s1[i] == s2[i] && i < len1 && i < len2) ++i;
ex[0] = i;
pos = 0;
for (int i = 1; i < len1; ++i) {
if (nex[i-pos] + i < ex[pos] + pos) ex[i] = nex[i-pos];
else {
j = ex[pos] + pos - i;
if (j < 0) j = 0;
while (i+j < len1 && j < len2 && s1[i+j] == s2[j]) ++j;
ex[i] = j;
pos = i;
}
}
}
int n, m, a[maxn], mx[maxn];
void solve() {
for (int i = n - 1; ~i; i--)
scanf("%d", &a[i]);
get_ex(a, a, n, n);
for (int i = 1; i <= m; i++)
mx[i] = 0;
for (int i = 0; i < n; i++) {
if (i)
mx[a[i - 1]] = max(mx[a[i - 1]], ex[i] + 1);
mx[a[i]] = max(mx[a[i]], 1);
}
int ans = 0, cat = 1;
for (int i = 1; i <= m; i++) {
cat = 1ll * cat * 3 % mod;
int res = 1ll * (n + 1 - mx[i]) * cat % mod;
ans ^= res;
}
printf("%d\n", ans);
}
int main() {
while (~scanf("%d%d", &n, &m))
solve();
}
题意:有一个长度为 的序列,你可以给每个位置填0-9的一个数,有 个限制,每个限制 要求区间内的数相乘必须为9的倍数,问一共有多少种合法的填数方案。
解法:设 为当前已经填过的数中,倒数第二个3的位置在 ,最后一个3的位置在 ,假设当前在位置 ,我填了个0或者9,那么新的状态变成 ,那么 ,如果填了个3或者6,那么 ,填剩下的数状态不变: ,然后找到所有的右端点在 的限制条件区间 ,如果该区间只有一个3,显然非法,枚举 ,再枚举 ,将 设为0即可
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod = 1e9 + 7;
void add(int &x, int y) {
x += y;
if (x >= mod)
x -= mod;
if (x < 0)
x += mod;
}
vector<int> G[51];
int d[51][51], P[51], P2[51];
int main() {
int n, m, l, r;
P[0] = P2[0] = 1;
for (int i = 1; i <= 50; i++) {
P[i] = 1ll * P[i - 1] * 10 % mod;
P2[i] = 1ll * P2[i - 1] * 9 % mod;
}
while (~scanf("%d%d", &n, &m)) {
for (int i = 0; i <= n; i++) {
G[i].clear();
for (int j = i; j <= n; j++)
d[i][j] = 0;
}
d[0][0] = 1;
for (int i = 1; i <= m; i++) {
scanf("%d%d", &l, &r);
G[r].push_back(l);
}
int ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = i - 1; ~j; j--)
for (int k = j; ~k; k--)
if (d[k][j] != -1) {
add(d[i][i], 2ll * d[k][j] % mod);
add(d[j][i], 2ll * d[k][j] % mod);
d[k][j] = 1ll * d[k][j] * 6 % mod;
}
for (auto v : G[i]) {
for (int j = 0; j < v; j++)
for (int k = j; k <= i; k++)
d[j][k] = -1;
}
}
for (int i = 0; i <= n; i++)
for (int j = i; j <= n; j++)
if (d[i][j] != -1)
add(ans, d[i][j]);
printf("%d\n", ans);
}
}