abc419
很久没写过这种东西了。
A
非常有必要说!但是不知道从哪里说。所以给个代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
string str;cin >> str;
if(str == "red")cout << "SSS";
else if(str == "blue")cout << "FFF";
else if(str == "green")cout << "MMM";
else if(str == "yellow")cout << "RRR";
else cout << "Unknown";
return 0;
}
B
没必要说的。
C
卡了非常久。
给个式子:\(\max(\lceil \dfrac{maxx - minx}{2} \rceil,\lceil \dfrac{maxy - miny}{2} \rceil)\)。
D
发现操作即为将 \(l \sim r\) 的数反转。然后前缀和维护,做完了。但是怎么还罚了一发啊。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 10;
string S,T;
int n,m,c[maxn];
int main()
{
cin >> n >> m >> S >> T;S = " " + S;T = " " + T;
while(m--)
{
int l,r;cin >> l >> r;
c[l] ^= 1;c[r + 1] ^= 1;
}
for(int i = 1;i <= n;i++)c[i] ^= c[i - 1];
for(int i = 1;i <= n;i++)cout << (c[i] ? T[i] : S[i]);
return 0;
}
E
脑电波。注意到 \(s_j \equiv s_{l+j} \pmod m\)。然后令 \(dp_{i,j}\) 表示所有 \(k\times l + i\) 的位置的数全部除 \(m\) 模 \(j\),然后随便转移。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 510;
int n,m,l,ans,pos[maxn][maxn],dp[maxn][maxn];vector<int> vec[maxn];
int calc(int j,int u){return (u - j % m + m) % m;}
signed main()
{
cin >> n >> m >> l;
for(int i = 1;i <= n;i++)
{
int x;cin >> x;
vec[i % l].push_back(x);
}
for(int i = 0;i < l;i++)for(int j = 0;j < m;j++)for(int u : vec[i])pos[i][j] += calc(u,j);
memset(dp,63,sizeof(dp));dp[0][0] = 0;
for(int i = 1;i <= l;i++)
{
for(int j = 0;j < m;j++)
{
for(int k = 0;k < m;k++)
{
dp[i][j] = min(dp[i][j],dp[i - 1][k] + pos[i % l][(j - k + m) % m]);
}
}
}
cout << dp[l][0];
return 0;
}
F
唐的没边,但是更唐的是我。
定义 \(dp_{l,u,m}\) 表示长度为 \(l\) 的字符串,当前在自动机状态 \(u\),已经匹配的字符串集合为 \(m\) 的数量。
然后转移就是:
其中 \(v\) 为 \(u\) 经过字符 \(c\) 的转移得到的状态 \(v\),\(S_v\) 表示以 \(v\) 节点为结尾的字符串数量,结束。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod = 998244353;
const int maxn = 1e5 + 10;
namespace ACAM
{
int tr[maxn][30],fail[maxn],tot;
char s[maxn];int nodeS[maxn];
void insert(int id)
{
cin >> s + 1;int u = 0;
for(int i = 1;s[i];i++)
{
if(!tr[u][s[i] - 'a']) tr[u][s[i] - 'a'] = ++tot;
u = tr[u][s[i] - 'a'];
}
nodeS[u] |= (1 << id);
}
queue<int> q;
void build()
{
for(int i = 0;i < 26;i++)if(tr[0][i])q.push(tr[0][i]);
while(q.size())
{
int u = q.front();q.pop();
for(int i = 0;i < 26;i++)
{
if(tr[u][i])fail[tr[u][i]] = tr[fail[u]][i],q.push(tr[u][i]);
else tr[u][i] = tr[fail[u]][i];
nodeS[tr[u][i]] |= nodeS[fail[tr[u][i]]];
}
}
}
}using namespace ACAM;
int dp[105][105][500];
signed main()
{
int n,L;cin >> n >> L;
for(int i = 0;i < n;i++)insert(i);
build();dp[0][0][0] = 1;
for(int l = 0;l < L;l++)
{
for(int u = 0;u <= tot;u++)
{
for(int S = 0;S < 1 << n;S++)
{
if(!dp[l][u][S])continue;
for(int i = 0;i < 26;i++)
{
int v = u;
while(v && !tr[v][i])v = fail[v];
int nS = S | nodeS[tr[v][i]];
dp[l + 1][tr[v][i]][nS] = (dp[l + 1][tr[v][i]][nS] + dp[l][u][S]) % mod;
}
}
}
}
int ans = 0;
for(int i = 0;i <= tot;i++)ans = (ans + dp[L][i][(1 << n) - 1]) % mod;
cout << ans;
return 0;
}
G
唐的没边,但是更唐的是我。
\(\text{Sol 1}\)
先找出一颗 DFS 树,那么这棵树上会对于答案会有贡献的就是这棵树上的后向边。
然后考虑把所有的后向边的两个端点拉出来,建一颗虚树。此时你发现这个虚树的点数是 \(2k\) 的,其中 \(k = m - n + 1\)。那么你可以直接用 \(\mathrm O(k2^k)\) 去暴力枚举整一颗树,然后去计算所有的路径。
code。
\(\text{Sol 2}\)
注意到 \(m - n \le 20\),所以考虑使用广义串并连通图方法来做这个题。
广义串并连通图方法对于图长什么样没有任何限制。
接下来考虑进行以下几种操作:
- 删一度点:选择一个度数为 \(1\) 的点并删掉它和与它连接的边。
- 缩二度点:选择一个度数为 \(2\) 的点,用一条边替换它和与它相连的两条边。
- 叠重边:选择两条重边,用一条边替换它们。
做完以上的操作之后,我们知道一定只剩度数 \(\ge 3\) 的点了,所以 \(3n \le 2m\)。那么我们就有 \(n \le 2k,m \le 3k\)。
那么接下来的操作就和 \(\text{Sol 1}\) 后面的操作一样了。
code。

浙公网安备 33010602011771号