ICPC2023 合肥站
B. Queue Sorting
tag: Dilworth DP
我们可以发现,我们将原序列建图,让小的在前面的数连向大的在后面的数,那么我们就可以将问题转化为:求图中的最小链覆盖是否 \(\leq 2\)
然后我们接着使用 Dilworth 定理,就变成了判断最长反链是否 \(\leq 2\)
即:序列的逆序列的最长上升子序列长度不超过 \(2\)
即求:有多少种不同的序列,它的最长上升子序列长度不超过2。
之后的话,先摆烂了
C. Cyclic Substrings
tag: PAM
回文自动机的板子,但是本人抄板子导致原本应该 \(-'0'\) 的,结果减成 \(-'a'\) 了,导致调了半天
code
#include <bits/stdc++.h>
#define endl "\n"
using namespace std;
const int NN = 6e6 + 1024;
int n;
string s;
int len[NN], fail[NN], go[NN][26], last, pam_cnt;
long long cnt[NN];
void clgo(int x){memset(go[x], 0, sizeof(go[x]));}
void init()
{
fail[0] = pam_cnt = 1; len[1] = -1;
last = 0; clgo(0); clgo(1);
}
int getfail(int n,int p)
{
// cout << '1' << endl;
while(s[n-len[p]-1] != s[n]) p = fail[p];
return p;
}
void extend(int n)
{
int p = getfail(n,last), c = s[n] - '0';
if(!go[p][c])
{
int q = ++pam_cnt, now = p;
clgo(q);
len[q] = len[p] + 2;
p = getfail(n, fail[p]);
fail[q] = go[p][c]; last = go[now][c] = q;
}
else last = go[p][c];
if(n >= ::n/2) ++cnt[last];
}
const long long MOD = 998244353;
long long ans;
signed main()
{
ios::sync_with_stdio(false), cin.tie(0);
init();
cin >> n >> s;
s = s + s; n *= 2;
for(int i = 0; i < n; ++i)
extend(i);
for(int u = pam_cnt; u >= 2; --u)
{
cnt[fail[u]] += cnt[u];
if(len[u] <= n/2) ans += 1ll * cnt[u] * cnt[u] % MOD * len[u] % MOD;
ans %= MOD;
}
cout << ans % MOD;
return 0;
}
E. Matrix Distances
计算所有同色单元格之间的曼哈顿距离之和
分开 \(x,y\) 坐标分别计算即可
code
#include <bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
unordered_map<int,int>h;
vector<int>a[1000005],b[1000005];
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,m;
cin>>n>>m;
int tot=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
int x;
cin>>x;
if(h.find(x)==h.end())
{
h[x]=++tot;
}
a[h[x]].push_back(i);
b[h[x]].push_back(j);
}
}
int ans=0;
for(int i=1;i<=tot;i++)
{
sort(a[i].begin(),a[i].end());
sort(b[i].begin(),b[i].end());
int cur=0;
for(int j=0;j<a[i].size();j++)
{
ans=ans+(a[i][j]*j-cur)*2;
cur+=a[i][j];
}
cur=0;
for(int j=0;j<b[i].size();j++)
{
ans=ans+(b[i][j]*j-cur)*2;
cur+=b[i][j];
}
}
cout<<ans<<endl;
return 0;
}
F. Colorful Balloons
tag: 摩尔投票
题意就是求最后是否有数量大于 \(\frac n 2\) 的元素
当然,\(map\) 也可以过
code
#include <bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
map<string,int>q;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin>>n;
string ans="uh-oh";
for(int i=1;i<=n;i++)
{
string s;
cin>>s;
q[s]++;
if(q[s]*2>n)
{
ans=s;
}
}
cout<<ans<<endl;
return 0;
}
G. Streak Manipulation
tag: 二分答案 DP
我们首先二分第 \(k\) 长的 \(1\dots 1\) 串的长度 \(mid\)
那么我们现在的程序就简化成为:求是否能够通过最多进行 \(m\) 次操作,使得长度大于 \(mid\) 的 \(1\dots 1\) 串的个数 \(\geq k\)
我们设 \(f_{i,j,0/1}\) 表示 对于前 \(i\) 个数,已经找到了 \(j\) 个满足条件的串,当前位置是否是一个结尾所需要的修改次数
复杂度:\(O(nk\log n)\)
code
#include <bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
int sum[200005];
int f[200005][6],g[200005][6];
deque<int>q[6];
int n,m,k;
string s;
bool check(int len)
{
for(int i=0;i<=n;i++)
{
for(int j=0;j<=k;j++)
{
f[i][j]=g[i][j]=INT_MAX;
}
}
for(int i=0;i<=k;i++)
{
q[i].clear();
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=k;j++)
{
if(i-len+1>=1)
{
while(q[j-1].size()>1)
{
if(q[j-1][1]<=i-len)
{
q[j-1].pop_front();
}
else
{
break;
}
}
if(j==1)
{
f[i][j]=len-(sum[i]-sum[i-len]);
}
else if(q[j-1].size())
{
f[i][j]=g[q[j-1].front()-1][j-1]+len-(sum[i]-sum[i-len]);
}
}
g[i][j]=min(g[i-1][j],f[i][j]);
if(s[i-1]=='0')
{
q[j].push_back(i);
}
}
}
return g[n][k]<=m;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m>>k;
cin>>s;
for(int i=1;i<=n;i++)
{
sum[i]=sum[i-1]+s[i-1]-'0';
}
if(check(1)==false)
{
cout<<-1<<endl;
return 0;
}
int l=1,r=n;
while(l<r)
{
int mid=(l+r+1)>>1;
if(check(mid))
{
l=mid;
}
else
{
r=mid-1;
}
}
cout<<l<<endl;
return 0;
}
J. Takeout Delivering
tag: 枚举 最短路
题意就是求从 \(1\) 走到 \(n\) 的 最大和次大 的边长和最小
个人一开始想到的方法是 二分答案 + 分层图 判断连通性,但是发现对于和这个东西,我们不能很好地处理
然后就想到了枚举最长边,然后我们预处理从 起点和终点 到点 \(x\) 的所有 路径的边权最大值 的最小值
然后最后就正常合并了
code
#include <bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int NN = 3e5 + 8;
int n,m;
struct Edge
{
int v,val;
bool operator < (const Edge &x)const
{
return val > x.val;
}
};
vector<Edge>a[NN];
int f[NN],g[NN];
void dijkstra1()
{
priority_queue<Edge>q;
q.push({1,0}); f[1] = 0;
while(!q.empty())
{
int u = q.top().v,val = q.top().val;
q.pop();
if(val != f[u]) continue;
for(auto e : a[u])
{
int v = e.v;
if(f[v] > max(e.val, f[u]))
{
f[v] = max(e.val,f[u]);
q.push({v,f[v]});
}
}
}
}
void dijkstra2()
{
priority_queue<Edge>q;
q.push({n,0}); g[n] = 0;
while(!q.empty())
{
int u = q.top().v,val = q.top().val;
q.pop();
if(val != g[u]) continue;
for(auto e : a[u])
{
int v = e.v;
if(g[v] > max(e.val, g[u]))
{
g[v] = max(e.val,g[u]);
q.push({v,g[v]});
}
}
}
}
signed main()
{
ios::sync_with_stdio(false),cin.tie(0);
memset(f,0x3f,sizeof(f)), memset(g,0x3f,sizeof(g));
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
a[u].push_back({v,w});
a[v].push_back({u,w});
}
dijkstra1();
dijkstra2();
int ans = 1e18;
for(auto e : a[1])
{
int v = e.v, val = e.val;
if(v == n) ans = min(ans,val);
}
for(int u = 1; u <= n; ++u)
{
for(auto e: a[u])
{
int v = e.v, val = e.val;
// if(v == 1 || v == n) continue;
if(f[u] <= val && g[v] <= val) ans = min(ans,val + max(f[u],g[v]));
}
}
// for(int i = 1; i <= n; ++i)
// {
// cout << f[i] << ' ';
// }
// cout << '\n';
// for(int i = 1; i <= n; ++i) cout << g[i] << ' ';
// cout << '\n';
cout << ans;
return 0;
}
本文来自博客园,作者:ricky_lin,转载请注明原文链接:https://www.cnblogs.com/rickylin/p/19171181/ICPC_2023_Hefei

浙公网安备 33010602011771号