20201029模拟赛总结
T1
看到这题第一眼感觉这不是直接暴力就可以吗……
尽管如此,我还是莫名其妙的写了一个 \(KMP\) 尽管什么也没有用到,然后它跑 \(RE\) 了导致 \(60pts\) 溜了。
其实我们只需要循环比较,比较长度是较长字符串的二倍即可啦!
T2
这题的根号居然是实数意义下的,我以为是整数意义下直接懵逼爆零滚粗 qwq 。
我们化简 \(\sqrt {m} = k\sqrt b\) , 发现若要等式成立那么 \(\sqrt x\) 必须是 \(\sqrt b\) 的倍数。
那么也就是说我们要求出数列 \(a_1 , a_2 , a_3 , \dots , a_{n-1} , a_n\) 使得 \(\sum\limits_{i=1}^n a_i = k\) 即可,数量可用插板法求解。
T3
这道题一眼就发现不可做,然而我却成功的在样例特水无大样例的情况下通过了这道题!!!
我们考虑 \(DP\) ,设状态 \(dp[i][j][k]\) 为 前 \(i\) 个字母现在匹配到第 \(j\) 个句式的第 \(k\) 个单词的方案数,然后在单词结尾处转移即可,可以使用 AC自动机 处理。
code:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define ll long long
using namespace std;
int read()
{
int a = 0,x = 1;char ch = getchar();
while(ch > '9' || ch < '0') {if(ch == '-') x = -1;ch = getchar();}
while(ch >= '0' && ch <= '9') {a = a*10 + ch-'0';ch = getchar();}
return a*x;
}
const int N=1007,P=1000000007;
int n,m;
char s[N];
int ch[N][27],vis[N],p[N],len[N],nxt[N],cnt;
bool ins[N][11];
void add(int num)
{
int t = 1;len[num] = strlen(s+1);
for(int i = 1;i <= len[num];i ++){
if(!ch[t][s[i]-'a']) ch[t][s[i]-'a'] = ++cnt;
t = ch[t][s[i]-'a'];
}
if(!vis[t]) vis[t] = num;
int tmp = read();
for(int i = 1;i <= tmp;i ++) {
int a = read();
if(!ins[vis[t]][a]) {p[num] ++,ins[vis[t]][a] = 1;}
}
}
queue<int>q;
void init()
{
for(int i = 0;i < 26;i ++) ch[0][i] = 1;
q.push(1);
while(!q.empty()) {
int u = q.front();q.pop();
printf("%d\n",u);
for(int i = 0;i < 26;i ++) {
if(!ch[u][i]) ch[u][i] = ch[nxt[u]][i];
else {
nxt[ch[u][i]] = ch[nxt[u]][i];
q.push(ch[u][i]);
}
}
// getchar();
}
}
int num[12],wo[12][12];
ll dp[N][12][12],f[N];
#define fa nxt
int find(int s,int i)
{
if(!s) return s;
if(!vis[s]) return fa[s] = find(fa[s],i);
find(fa[s],i);
for(int j = 1;j <= m;j ++) {
for(int k = 1;k <= num[j];k ++) {
if(ins[vis[s]][wo[j][k]]) {
if(k > 1) {
(dp[i][j][k] += dp[i-len[vis[s]]][j][k-1]) %= P;
} else (dp[i][j][k] += f[i-len[vis[s]]]) %= P;
}
}
}
return s;
}
#undef fa
int main()
{
freopen("word.in","r",stdin);
freopen("word.out","w",stdout);
n = read(),m = read(),cnt = 1;
for(int i = 1;i <= n;i ++) {
scanf("%s",s+1);
add(i);
}
init();
for(int i = 1;i <= m;i ++) {
num[i] = read();
for(int j = 1;j <= num[i];j ++) wo[i][j] = read();
}
scanf("%s",s+1);int l = strlen(s+1);
f[0] = 1;for(int i = 1,t = 1;i <= l;i ++) {
t = ch[t][s[i]-'a'];find(t,i);
for(int j = 1;j <= m;j ++) (f[i] += dp[i][j][num[j]]) %= P;
}
printf("%lld",f[l]);
return 0;
}