#include<bits/stdc++.h>usingnamespace std;// #define int long long#definedoublelongdoubleusing i64 =longlong;typedef pair<int,int> PII;typedef pair<int,char> PIC;typedef pair<double,double> PDD;typedef pair<PII,int> PIII;typedef pair<int, pair<int,bool>> PIIB;constint N =2e5+10;constint maxn =1e6;constint MAXN =100;constint mod =998244353;constint mod1 =954169327;constint mod2 =906097321;constint INF =0x3f3f3f3f3f3f3f3f;voidsolve(){int n; cin >> n;
vector<int>a(n +1),pre(n +1);for(int i =1; i <= n; i++){
cin >> a[i];
pre[i]= pre[i -1]+ a[i];}
vector<vector<int>>c(pre[n]+1,vector<int>(pre[n]+1));
c[0][0]=1;for(int i =1; i <= pre[n]; i++){
c[i][0]=1;for(int j =1; j <= i; j++){
c[i][j]=(c[i][j]+ c[i -1][j -1]+ c[i -1][j])% mod;}}
vector<vector<int>>dp(n +1,vector<int>(pre[n]+1));
dp[0][0]=1;for(int i =0; i < n; i++){for(int j =0; j <= pre[i]; j++)// 第i个位置最末的下降子序列开头{if(dp[i][j]){
dp[i +1][j]=(dp[i +1][j]+ dp[i][j])% mod;for(int k = j +1; k < pre[i +1]; k++)// 把i+1都放在[j+1,k]{// 枚举多少i+1放在末尾int minn =max(0, a[i +1]-(k - j));int maxx =min(a[i +1]-1, pre[i +1]- k -1);for(int x = minn; x <= maxx; x++)
dp[i +1][k]=(dp[i +1][k]+(1ll* dp[i][j]* c[k - j -1][a[i +1]- x -1]% mod))% mod;}}}}int ans =0;for(int i =0; i <= pre[n]; i++) ans =(ans + dp[n][i])% mod;
cout << ans <<'\n';}signedmain(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);int t =1;// cin >> t;while(t--){solve();}return0;}
C. Cyclic Substrings(回文自动机)
将原字符串复制一遍,防止重复,结尾大于
n
n
n 的才加入cnt中
之后就是回文自动机的板子
#include<bits/stdc++.h>usingnamespace std;// #define int long long#definedoublelongdoubleusing i64 =longlong;typedef pair<int,int> PII;typedef pair<int,char> PIC;typedef pair<double,double> PDD;typedef pair<PII,int> PIII;typedef pair<int, pair<int,bool>> PIIB;constint N =6e6+10;constint maxn =1e6;constint MAXN =100;constint mod =998244353;constint mod1 =954169327;constint mod2 =906097321;constint INF =0x3f3f3f3f3f3f3f3f;int ans =0;/*
---------------回文自动机PAM---------------
- 传入字符串下标从0开始
- 本质不同的回文子串个数
- 所有回文子串个数
- 每种回文串出现的次数 cnt(需要get_cnt)
- 每种回文串的长度 len
- 以下标 i 为结尾的回文串的个数 sed
- 每个回文串在原串中出现的起始位置 record
*/structPAM{
string s;int n;int nxt[N][10];int fail[N];// 当前节点最长回文后缀的节点int len[N];// 当前节点表示的回文串的长度int cnt[N];// 当前节点回文串的个数, 在getcnt后可得到全部// int sed[N]; // 以当前节点为后缀的回文串的个数// int record[N]; // 每个回文串在原串中出现的位置int tot;// 节点个数int last;// 上一个节点voidinit(){
tot =0;for(int i =0; i < N; i ++){
fail[i]= cnt[i]= len[i]=0;for(int j =0; j <10; j ++) nxt[i][j]=0;}}intnewnode(int lenx){for(int i =0; i <26; i++)
nxt[tot][i]=0;
cnt[tot]=0;
len[tot]= lenx;return tot;}voidbuild(string ss){
tot =0;newnode(0);
tot =1, last =0;newnode(-1);
fail[0]=1;
n = ss.size();
s =" "+ ss;}intgetfail(int x,int n){while(n - len[x]-1<=0|| s[n - len[x]-1]!= s[n])
x = fail[x];return x;}voidinsert(char cc,int pos,int op){int c = cc -'0';int p =getfail(last, pos);if(!nxt[p][c]){
tot++;newnode(len[p]+2);
fail[tot]= nxt[getfail(fail[p], pos)][c];
len[tot]= len[p]+2;// sed[tot] = sed[fail[tot]] + 1;
nxt[p][c]= tot;}
last = nxt[p][c];
cnt[last]+= op;// record[last] = pos;}voidinsert(){for(int i =1; i <= n; i++){if(i <= n /2)insert(s[i], i,0);elseinsert(s[i], i,1);}}voidget_cnt(){for(int i = tot; i >0; i --){
cnt[fail[i]]+= cnt[i];if(i >=2&& len[i]<= n /2){
ans =(ans +1ll* cnt[i]* cnt[i]% mod * len[i]% mod)% mod;}}}intget_diff_cnt()// 本质不同的回文子串个数{return tot -1;}intget_all_cnt()// 所有回文子串个数(本质相同的多次计算){int sum =0;get_cnt();for(int i =2; i <= tot; i ++) sum += cnt[i];return sum;}} pam;//------------------------------------voidsolve(){int n; cin >> n;
string s; cin >> s;
s = s + s;
pam.init();
pam.build(s);
pam.insert();
pam.get_cnt();
cout << ans <<'\n';}signedmain(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);int t =1;// cin >> t;while(t--){solve();}return0;}
E. Matrix Distances(前缀和)
分别统计横坐标和纵坐标的贡献,统计方式是用前缀和
坑点是需要离散化,直接map会T
#include<bits/stdc++.h>usingnamespace std;#defineintlonglong#definedoublelongdoubleusing i64 =longlong;typedef pair<int,int> PII;typedef pair<int,char> PIC;typedef pair<double,double> PDD;typedef pair<int, PII> PIII;typedef pair<int, pair<int,bool>> PIIB;constint N =1e3+10;constint maxn =1e6;constint MAXN =100;constint mod =998244353;constint mod1 =954169327;constint mod2 =906097321;constint INF =0x3f3f3f3f3f3f3f3f;int idx;int g[N][N];voidsolve(){int n, m; cin >> n >> m;
vector<int> tt;
map<int,int> mp;for(int i =1; i <= n; i ++){for(int j =1; j <= m; j ++){
cin >> g[i][j];
tt.push_back(g[i][j]);}}sort(tt.begin(), tt.end());
tt.erase(unique(tt.begin(), tt.end()), tt.end());for(int i =0; i < tt.size(); i ++){
mp[tt[i]]= i +1;}
vector<vector<int>>x(tt.size()+10),y(tt.size()+10);for(int i =1; i <= n; i ++){for(int j =1; j <= m; j ++){int tmp = mp[g[i][j]];
x[tmp].push_back(i);
y[tmp].push_back(j);}}int ans =0;for(auto t : x){if(t.size()<=1)continue;sort(t.begin(), t.end());
vector<int>pre(t.size()+2);
pre[0]= t[0];for(int i =1; i < t.size(); i ++){
pre[i]= pre[i -1]+ t[i];
ans += t[i]*(i +1)- pre[i];}}for(auto t : y){if(t.size()<=1)continue;sort(t.begin(), t.end());
vector<int>pre(t.size()+2);
pre[0]= t[0];for(int i =1; i < t.size(); i ++){
pre[i]= pre[i -1]+ t[i];
ans += t[i]*(i +1)- pre[i];}}
cout << ans *2<<'\n';}signedmain(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);int t =1;// cin >> t;while(t--){solve();}return0;}
F. Colorful Balloons(签到)
没看题,偷一下队友的码
#include<iostream>#include<cstring>#include<cmath>#include<cstdio>#include<vector>#include<map>#include<algorithm>#include<queue>#include<iomanip>#include<random>#include<set>usingnamespace std;typedeflonglong LL;typedef __int128 i128;typedefunsignedlonglong ULL;typedefdouble db;voidAsuka(){int n;
map<string ,int>mp;
cin >> n;for(int i =1; i <= n ; i ++){
string s;
cin >> s;
mp[s]++;}for(auto t : mp){if(t.second > n /2){
cout << t.first <<'\n';return;}}
cout <<"uh-oh\n";return;}signedmain(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);int t =1;// cin >> t;while(t --){Asuka();}return0;}
G. Streak Manipulation(二分+dp)
首先这种最大最小值的问题很容易想到二分,我们二分最终答案,也就是第 k 长连续 1 子段的最大长度
怎么实现 check 函数呢,看到 k 最大为 5 ,考虑能不能用dp
dp[i][j][0/1] 表示前 i 个字符中有 j 段长度大于等于 mid 的连续 1 子串且第 i 位为 0/1 的最小操作数
更新方式:
若
s
[
i
]
=
′
0
′
s[i]='0'
s[i]=′0′
d
p
[
i
]
[
j
]
[
0
]
=
min
(
d
p
[
i
]
[
j
]
[
0
]
,
d
p
[
i
−
1
]
[
j
]
[
0
]
,
d
p
[
i
−
1
]
[
j
]
[
1
]
)
d
p
[
i
]
[
j
]
[
1
]
=
min
(
d
p
[
i
]
[
j
]
[
1
]
,
d
p
[
i
−
1
]
[
j
]
[
1
]
+
1
)
dp[i][j][0]=\min(dp[i][j][0],dp[i-1][j][0], dp[i-1][j][1])\\ dp[i][j][1]=\min(dp[i][j][1],dp[i-1][j][1]+1)
dp[i][j][0]=min(dp[i][j][0],dp[i−1][j][0],dp[i−1][j][1])dp[i][j][1]=min(dp[i][j][1],dp[i−1][j][1]+1)
若
s
[
i
]
=
′
1
′
s[i]='1'
s[i]=′1′
d
p
[
i
]
[
j
]
[
0
]
=
min
(
d
p
[
i
]
[
j
]
[
0
]
,
d
p
[
i
−
1
]
[
j
]
[
0
]
)
d
p
[
i
]
[
j
]
[
1
]
=
min
(
d
p
[
i
]
[
j
]
[
1
]
,
d
p
[
i
−
1
]
[
j
]
[
1
]
)
dp[i][j][0]=\min(dp[i][j][0],dp[i-1][j][0])\\ dp[i][j][1]=\min(dp[i][j][1],dp[i-1][j][1])
dp[i][j][0]=min(dp[i][j][0],dp[i−1][j][0])dp[i][j][1]=min(dp[i][j][1],dp[i−1][j][1])
同时,如果
i
≥
m
i
d
i\geq mid
i≥mid 且
j
≥
0
j\geq 0
j≥0
d
p
[
i
]
[
j
]
[
1
]
=
min
(
d
p
[
i
]
[
j
]
[
1
]
,
d
p
[
i
−
m
i
d
]
[
j
−
1
]
[
0
]
+
p
r
e
[
i
]
−
p
r
e
[
i
−
m
i
d
]
)
dp[i][j][1]=\min(dp[i][j][1],dp[i-mid][j-1][0]+pre[i]-pre[i-mid])
dp[i][j][1]=min(dp[i][j][1],dp[i−mid][j−1][0]+pre[i]−pre[i−mid])
其中,
p
r
e
pre
pre 是 0 个数的前缀和
#include<bits/stdc++.h>usingnamespace std;#defineintlonglong#definedoublelongdoubleusing i64 =longlong;typedef pair<int,int> PII;typedef pair<int,char> PIC;typedef pair<double,double> PDD;typedef pair<PII,int> PIII;typedef pair<int, pair<int,bool>> PIIB;typedef pair<PII, PII> PIIII;constint N =1e5+10;constint maxn =1e6;constint MAXN =100;constint mod =998244353;constint mod1 =954169327;constint mod2 =906097321;constint INF =0x3f3f3f3f3f3f3f3f;voidsolve(){int n, m, k; cin >> n >> m >> k;
string s; cin >> s;
s =" "+ s;
vector<int>pre(n +1);for(int i =1; i <= n; i ++) pre[i]= pre[i -1]+(s[i]=='0');
vector<vector<vector<int>>>dp(n +1,vector<vector<int>>(k +1,vector<int>(2, INF)));auto check =[&](int x){for(int i =0; i <= n; i ++){for(int j =0; j <= k; j ++){
dp[i][j][0]= dp[i][j][1]= INF;}}
dp[0][0][0]= dp[0][0][1]=0;for(int i =1; i <= n; i ++){for(int j =0; j <= k; j ++){if(s[i]=='0'){
dp[i][j][0]=min({dp[i][j][0], dp[i -1][j][0], dp[i -1][j][1]});
dp[i][j][1]=min(dp[i][j][1], dp[i -1][j][1]+1);}else{
dp[i][j][0]=min(dp[i][j][0], dp[i -1][j][0]);
dp[i][j][1]=min(dp[i][j][1], dp[i -1][j][1]);}if(i >= x && j >=1){
dp[i][j][1]=min(dp[i][j][1], dp[i - x][j -1][0]+ pre[i]- pre[i - x]);}}}return(min(dp[n][k][0], dp[n][k][1])<= m);};int l =0, r = n;while(l < r){int mid = l + r +1>>1;if(check(mid)) l = mid;else r = mid -1;}if(r >0) cout << r <<'\n';else cout <<-1<<'\n';}signedmain(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);int t =1;// cin >> t;while(t--){solve();}return0;}
J. Takeout Delivering(dijkstra+思维)
枚举每一条边作为最终答案的边,然后看它的两个端点到 1 和 n 的距离更新最终答案
#include<bits/stdc++.h>usingnamespace std;#defineintlonglong#definedoublelongdoubleusing i64 =longlong;typedef pair<int,int> PII;typedef pair<int,char> PIC;typedef pair<double,double> PDD;typedef pair<PII,int> PIII;typedef pair<int, pair<int,bool>> PIIB;constint N =1e3+10;constint maxn =1e6;constint MAXN =100;constint mod =998244353;constint mod1 =954169327;constint mod2 =906097321;constint INF =0x3f3f3f3f3f3f3f3f;structedge{int a, b, c;};voidsolve(){int n, m; cin >> n >> m;
vector<vector<PII>>g(n +1);
vector<structedge>e(m);for(int i =0; i < m; i ++){int a, b, c; cin >> a >> b >> c;
e[i]={a, b, c};
g[a].push_back({b, c});
g[b].push_back({a, c});}
vector<int>dist1(n +1, INF),dist2(n +1, INF);auto dijkstra =[&](int rt, vector<int>&dist){
vector<bool>st(n +1);
priority_queue<PII, vector<PII>, greater<PII>> pq;
pq.push({0, rt});
dist[rt]=0;while(pq.size()){auto t = pq.top();
pq.pop();int v = t.second, maxx = t.first;if(st[v])continue;
st[v]=true;for(int i =0; i < g[v].size(); i ++){int j = g[v][i].first, w = g[v][i].second;if(st[j])continue;if(dist[j]>max(dist[v], w)){
dist[j]=max(dist[v], w);
pq.push({dist[j], j});}}}};dijkstra(1, dist1);dijkstra(n, dist2);int ans = INF;for(int i =0; i < m; i ++){auto[a, b, c]= e[i];int tmp =min(max(dist1[a], dist2[b]),max(dist1[b], dist2[a]));if(tmp <= c) ans =min(ans, tmp + c);}
cout << ans <<'\n';}signedmain(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);int t =1;// cin >> t;while(t--){solve();}return0;}