当前位置: 首页 > news >正文

OIFC NOI2023省队集训

T1 绕口令 twister

字符串


题意

给定环形字符串 \(s\),对 \(k\)\(1\)\(n\),判断是否能删去一个长 \(k\) 子段,使得剩余部分无相邻相同字符。


考虑已有的相邻相同字符,必须截断。再删去一个子段可能导致剩余部分的两端变为相同,则问题可转为子段中是否存在距离为 \(k\) 的字符不同的位置。

做法1

考虑暴力做法,枚举 \(i\)\(l\)\(r\),再枚举 \(j\)\(i+1\)\(r\),如果 \(s_{j-1}=s_j\) 直接 break。考虑优化,发现只有 \(s_j=s_l\)\(j-l\) 需要继续考虑 \((l+1,j+1)\),如果仍相等,会继续判断 \((l+2,j+2)\),一直进行下去知道不相等或碰到边界。发现碰到边界当且仅当 \(lcp(s_l,s_j)=r-j+1\) 用扩展 KMP 即可判断。

做法2

考虑不存在距离为 \(k\) 的字符不同的位置相当于 \(s[l:r-k]=s[l+k:r]\),用字符串哈希/KMP即可判断。


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<int,ll> pil;
typedef pair<ll,int> pli;
typedef pair<ll,ll> pll;
template<typename T>
void chkmin(T &x,const T &y){x=min(x,y);}
template<typename T>
void chkmax(T &x,const T &y){x=max(x,y);}
const int inf=0x3f3f3f3f;
const ll infll=0x3f3f3f3f3f3f3f3f;
const int MOD=998244353;
void add(int &x,int y){x+=y;if(x>=MOD) x-=MOD;
}
int qpow(int a,ll b){int mul=1;while(b){if(b&1) mul=(ll)mul*a%MOD;a=(ll)a*a%MOD;b>>=1;}return mul;
}
const int N=2000005;
int n,ans[N],vis[N],len[N];
string s;
void calc(int l,int r){int box=l;len[l]=0;for(int i=0;i<(r-l+1);i++) vis[i]=0;vis[0]=1;for(int i=l+1;i<=r;i++){if(i<box+len[box]) len[i]=min(len[i-box+l],box+len[box]-i);else len[i]=0;while(i+len[i]<=r&&s[l+len[i]]==s[i+len[i]]) len[i]++;if(i+len[i]>box+len[box]) box=i;if(i+len[i]<=r) vis[i-l]=1;}
}
bool solve(int Case){if(!(cin>>s)) return false;cout<<"Case "<<Case<<": ";n=s.size();s=" "+s+s;for(int i=0;i<n;i++) ans[i]=0;ans[n-1]=1;vector<int> vec;for(int i=1;i<=n;i++) if(s[i]==s[i+1]) vec.push_back(i);if(vec.empty()){calc(1,n);ans[0]=1;for(int i=0;i<n;i++){if(i) ans[i-1]|=vis[i];ans[n-i-1]|=vis[i];}for(int i=0;i<n;i++) cout<<ans[i];cout<<'\n';return true;}for(int ind=0;ind<vec.size();ind++){int i=vec[ind],j=vec[(ind+1)%vec.size()];if(j<=i) j+=n;calc(i+1,j);for(int k=0;k<j-i;k++) ans[n-k-1]|=vis[k];}for(int i=0;i<n;i++) cout<<ans[i];cout<<'\n';return true;
}
int main(){#ifndef JZQfreopen("twister.in","r",stdin);freopen("twister.out","w",stdout);#endifios::sync_with_stdio(false);int T=0;while(++T&&solve(T));return 0;
}

T2 图论 graph

图论、网络流、匹配


题意

给定一个有向图,图上的一些边是“重要的”。你的任务是,求出至少需要多少条路径,才能覆盖所有“重要的”边至少一次。

路径可以不是简单路径,亦即可以经过同一个点或者同一条边多次。


做法1

缩强连通分量,把必经边拆成两条边+一个必经点。暴力的做法是,求传递闭包,取出必经点的生成子图求最小连覆盖。考虑最小连覆盖等于点数-拆点二分图最大匹配,传递闭包可以直接放在右部点内部。

具体地,对缩点拆边后的图 \(G=(V,E)\),对 \((u,v)\in E\),在拆点二分图上加入容量为 \(1\)\((u,v')\) 和容量为 \(+\infty\)\((u',v')\);对必经点 \(u\),在拆点二分图上加入容量为 \(+\infty\)\((S,u)\)\((u',T)\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<int,ll> pil;
typedef pair<ll,int> pli;
typedef pair<ll,ll> pll;
template<typename T>
void chkmin(T &x,const T &y){x=min(x,y);}
template<typename T>
void chkmax(T &x,const T &y){x=max(x,y);}
const int inf=0x3f3f3f3f;
const ll infll=0x3f3f3f3f3f3f3f3f;
const int MOD=998244353;
void add(int &x,int y){x+=y;if(x>=MOD) x-=MOD;
}
int qpow(int a,ll b){int mul=1;while(b){if(b&1) mul=(ll)mul*a%MOD;a=(ll)a*a%MOD;b>>=1;}return mul;
}
const int N=50005,M=100005;
int n,m,dfn[N],low[N],tot,instack[N],id[N],vis[N+M];
stack<int> st;
vector<int> G[N];
void dfs(int u){dfn[u]=low[u]=++tot,instack[u]=1;st.push(u);for(auto v:G[u]){if(!dfn[v]){dfs(v);chkmin(low[u],low[v]);}else if(instack[v]) chkmin(low[u],dfn[v]);}if(dfn[u]==low[u]){while(st.top()!=u){int v=st.top();st.pop();id[v]=u,instack[v]=0;}st.pop();id[u]=u,instack[u]=0;}
}
namespace Flow{struct Edge{int u,v,c,f;Edge(){}Edge(int u,int v,int c,int f):u(u),v(v),c(c),f(f){}};Edge es[(M*12)+(N<<2)];int s,t,tot,dis[(N+M)<<1],vis[(N+M)<<1],cur[(N+M)<<1];vector<int> G[(N+M)<<1];void addEdge(int u,int v,int c){G[u].push_back(tot);es[tot++]=Edge(u,v,c,0);G[v].push_back(tot);es[tot++]=Edge(v,u,0,0);}bool bfs(){for(int i=s;i<=t;i++) dis[i]=inf,vis[i]=cur[i]=0;queue<int> q;q.push(s),dis[s]=0;while(q.size()){int u=q.front();q.pop();if(vis[u]) continue;vis[u]=1;for(auto eid:G[u]){auto e=es[eid];if(e.f<e.c&&dis[e.v]>dis[u]+1){dis[e.v]=dis[u]+1;q.push(e.v);}}}return dis[t]!=inf;}int dfs(int u,int t,int flow){if(u==t) return flow;int sum=0;for(int &i=cur[u];i<G[u].size();i++){auto &e=es[G[u][i]];if(e.f<e.c&&dis[e.v]==dis[u]+1){int tmp=dfs(e.v,t,min(flow-sum,e.c-e.f));e.f+=tmp,es[G[u][i]^1].f-=tmp;sum+=tmp;}if(sum==flow) break;}return sum;}int calc(){int sum=0;while(bfs()){sum+=dfs(s,t,inf);}return sum;}
}
void solve(){scanf("%d%d",&n,&m);vector<tuple<int,int,int>> es;for(int i=1;i<=m;i++){int u,v,t;scanf("%d%d%d",&u,&v,&t);es.push_back({u,v,t});G[u].push_back(v);}for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);vector<pii> es2;for(auto [u,v,t]:es){if(t&&id[u]==id[v]) vis[id[u]]=1;else if(t&&id[u]!=id[v]) vis[++n]=1,es2.push_back({id[u],n}),es2.push_back({n,id[v]});else if(id[u]!=id[v]) es2.push_back({id[u],id[v]});}Flow::s=0,Flow::t=(n<<1)+1;int cnt=0;for(int i=1;i<=n;i++) if(vis[i]){Flow::addEdge(0,i,1),Flow::addEdge(n+i,(n<<1)+1,1);cnt++;}for(auto [u,v]:es2) Flow::addEdge(u,n+v,1),Flow::addEdge(n+u,n+v,inf);printf("%d\n",cnt-Flow::calc());
}
int main(){#ifndef JZQfreopen("graph.in","r",stdin);freopen("graph.out","w",stdout);#endifint T=1;while(T--) solve();return 0;
}

做法2

直接跑有源汇上下界最小流,把必经边流量下界设为 \(1\),源点连向每一个点,每一个点连向汇点。

先求有源汇上下界可行流,注意要连一条源点到汇点容量为 \(+\infty\) 的边 \(e\),然后加超级源点、超级汇点。

跑出可行流后,删去附加边,从 \(T\)\(S\) 退流。

答案为 \(e\) 的流量 - 退流流量。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<int,ll> pil;
typedef pair<ll,int> pli;
typedef pair<ll,ll> pll;
template<typename T>
void chkmin(T &x,const T &y){x=min(x,y);}
template<typename T>
void chkmax(T &x,const T &y){x=max(x,y);}
const int inf=0x3f3f3f3f;
const ll infll=0x3f3f3f3f3f3f3f3f;
const int MOD=998244353;
void add(int &x,int y){x+=y;if(x>=MOD) x-=MOD;
}
int qpow(int a,ll b){int mul=1;while(b){if(b&1) mul=(ll)mul*a%MOD;a=(ll)a*a%MOD;b>>=1;}return mul;
}
const int N=50005,M=100005;
int n,m,s[N];
stack<int> st;
vector<int> G[N];
namespace Flow{struct Edge{int u,v,c,f;Edge(){}Edge(int u,int v,int c,int f):u(u),v(v),c(c),f(f){}};Edge es[(M<<1)+(N*6)];int tot,dis[N],vis[N],cur[N];vector<int> G[N];void addEdge(int u,int v,int c){G[u].push_back(tot);es[tot++]=Edge(u,v,c,0);G[v].push_back(tot);es[tot++]=Edge(v,u,0,0);}bool bfs(int s,int t){for(int i=1;i<=n;i++) dis[i]=inf,vis[i]=cur[i]=0;queue<int> q;q.push(s),dis[s]=0;while(q.size()){int u=q.front();q.pop();if(vis[u]) continue;vis[u]=1;for(auto eid:G[u]){auto e=es[eid];if(e.f<e.c&&dis[e.v]>dis[u]+1){dis[e.v]=dis[u]+1;q.push(e.v);}}}return dis[t]!=inf;}int dfs(int u,int t,int flow){if(u==t) return flow;int sum=0;for(int &i=cur[u];i<G[u].size();i++){auto &e=es[G[u][i]];if(e.f<e.c&&dis[e.v]==dis[u]+1){int tmp=dfs(e.v,t,min(flow-sum,e.c-e.f));e.f+=tmp,es[G[u][i]^1].f-=tmp;sum+=tmp;}if(sum==flow) break;}return sum;}int calc(int s,int t){int sum=0;while(bfs(s,t)){sum+=dfs(s,t,inf);}return sum;}
}
void solve(){scanf("%d%d",&n,&m);vector<tuple<int,int,int>> es;for(int i=1;i<=m;i++){int u,v,t;scanf("%d%d%d",&u,&v,&t);Flow::addEdge(u,v,inf);if(t) s[u]--,s[v]++;}int tmp=n;int s0=++n,t0=++n,s1=++n,t1=++n;for(int i=1;i<=tmp;i++) Flow::addEdge(s0,i,inf),Flow::addEdge(i,t0,inf);for(int i=1;i<=tmp;i++){if(s[i]>0) Flow::addEdge(s1,i,s[i]);else if(s[i]<0) Flow::addEdge(i,t1,-s[i]);}Flow::addEdge(t0,s0,inf);Flow::calc(s1,t1);int ans=Flow::es[Flow::tot-2].f;Flow::G[s0].pop_back(),Flow::G[t0].pop_back();printf("%d\n",ans-Flow::calc(t0,s0));
}
int main(){#ifndef JZQfreopen("graph.in","r",stdin);freopen("graph.out","w",stdout);#endifint T=1;while(T--) solve();return 0;
}

T3 配音演员 vocal

构造、图论


题意

做法

有没有可能不会无解?考虑证明,不难想到使用归纳法。

假设 \((n-1)\)-Benes 网络能够接受任意变换,只需决定每一个输入被放到左边还是右边。关注第一个交换器,发现0和1不能被放到相同一侧,进一步,发现第一行每一个交换器的输出都在不同两侧,最后一行每个交换器输入都在不同两侧。设 \(a_i\) 表示 \(i\) 被放到左/右侧,则 \(a_0\neq a_1,a_2\neq a_3,\dots\)\(a_{p_0}\neq a_{p_1},a_{p_2}\neq a_{p_3},\dots\)。这是一个黑白染色问题,直接跑即可。

考虑证明永远存在一个解:每一个点度数恒等于 \(2\),且边可以被黑白染色(第一行连的边不相邻、最后一行连的边不相邻),因此恒存在黑白染色方案。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<int,ll> pil;
typedef pair<ll,int> pli;
typedef pair<ll,ll> pll;
template<typename T>
void chkmin(T &x,const T &y){x=min(x,y);}
template<typename T>
void chkmax(T &x,const T &y){x=max(x,y);}
const int inf=0x3f3f3f3f;
const ll infll=0x3f3f3f3f3f3f3f3f;
const int MOD=998244353;
void add(int &x,int y){x+=y;if(x>=MOD) x-=MOD;
}
int qpow(int a,ll b){int mul=1;while(b){if(b&1) mul=(ll)mul*a%MOD;a=(ll)a*a%MOD;b>>=1;}return mul;
}
const int N=20,M=(1<<13)+5;
int n,p[M],q[M],tmp[M],ans[N<<1][M],vis[M],color[M];
vector<int> G[M];
void shuf(int p[],int l,int r){int n=r-l;for(int i=0;i<n;i++){int j=(i>>1);if(i&1) j|=(n>>1);tmp[j+l]=p[i+l];}for(int i=l;i<r;i++) p[i]=tmp[i];
}
bool dfs(int u,int t){if(vis[u]){if(t==color[u]) return true;return false;}vis[u]=1,color[u]=t;for(auto v:G[u]) if(!dfs(v,t^1)) return false;return true;
}
bool check(int l,int r){for(int i=l;i<r;i++) vis[p[i]]=color[p[i]]=0;for(int i=l;i<r;i++){if(vis[p[i]]) continue;if(!dfs(p[i],0)) return false;}return true;
}
bool solve(int l,int r,int row1,int row2){if(r-l==2){if(p[l]==q[l]) ans[row1][l>>1]=0;else ans[row1][l>>1]=1;return true;}for(int i=l;i<r;i++) G[p[i]].clear();for(int i=l;i<r;i+=2){G[p[i]].push_back(p[i+1]),G[p[i+1]].push_back(p[i]);G[q[i]].push_back(q[i+1]),G[q[i+1]].push_back(q[i]);}if(!check(l,r)) return false;for(int i=l;i<r;i+=2){ans[row1][i>>1]=color[p[i]];if(color[p[i]]) swap(p[i],p[i+1]);}for(int i=l;i<r;i+=2){ans[row2][i>>1]=color[q[i]];if(color[q[i]]) swap(q[i],q[i+1]);}int mid=(l+r)>>1;shuf(p,l,r),shuf(q,l,r);return solve(l,mid,row1+1,row2-1)&&solve(mid,r,row1+1,row2-1);
}
bool solve(bool flag){scanf("%d",&n);if(!n) return false;if(flag) printf("\n");for(int i=0;i<(1<<n);i++) scanf("%d",&q[i]);for(int i=0;i<(1<<n);i++) p[i]=i;if(!solve(0,1<<n,0,(n-1)<<1)){printf("impossible\n");return false;}for(int i=0;i<=((n-1)<<1);i++){for(int j=0;j<(1<<(n-1));j++) printf("%d",ans[i][j]);printf("\n");}return true;
}
int main(){#ifndef JZQfreopen("vocal.in","r",stdin);freopen("vocal.out","w",stdout);#endifbool flag=false;while(solve(flag)) flag=true;return 0;
}
http://www.hskmm.com/?act=detail&tid=35538

相关文章:

  • 实战案例:职行力如何利用纷享销客CRM实现人效管理数字化突围?
  • 2025年10月素材平台对比评测榜:高品图像领衔五强深度解析
  • 2025年10月儿童面霜品牌推荐:五强榜单对比评测与选购指南
  • Ansible
  • 示波器接地环路与电磁脉冲干扰:原理、影响及应对策略
  • 2025 年国内传感器厂家最新推荐排行榜:聚焦磁致伸缩 / 防爆 / 防水 / 线性 / 液位等多类型传感器,精选优质企业
  • 2025 年钢结构厂家最新推荐:优质品牌权威榜单发布,助力客户精准选择可靠合作伙伴
  • Palantir实体工程实践
  • 施普林格论文集:发展中国家城市废物流资源化利用与回收洞察
  • 0.9B PaddleOCR-VL 登顶 SOTA!GPUStack 高效推理部署实战指南
  • 【URP】Unity中的[摩尔纹]问题解决方案
  • 打印机已发送,但是不打印?一份全面的故障排除指南!
  • 2025 年雕塑源头厂家最新推荐排行榜:聚焦婚庆泡沫 / 玻璃钢 / 城市地标不锈钢等多品类,精选优质企业
  • SOAR技术与高效网络安全运营 - 教程
  • 2025《中国科学:信息科学》前沿学术沙龙暨2025年智能控制与计算科学国际学术会议
  • 2025 年板材厂家最新推荐排行榜:聚焦 ENF 级环保、零醛添加等高品质板材,精选前 6 强深度解析品牌优势与产品亮点
  • 在 .NET 9 中使用 Mapster 快速、高效的实现对象映射
  • 列出 Redux 的组件?
  • 2025 年房屋鉴定公司最新推荐权威排行榜:涵盖安全评估 / 承载力 / 工程质量 / 危房等多领域,精准指引选靠谱机构
  • 放大器保护机制的技术原理与实现策略
  • 2025 年最新推荐!国内优质球墨铸铁管厂家排行榜出炉,涵盖自来水 / 给水 / 排污 / 污水用 / 消防 / 饮用水场景适用品牌
  • 2025 年球墨铸铁管件厂家最新推荐排行榜:市政 / 给排水 / 污水处理用优质厂家权威甄选
  • 2025 年最新防火涂料厂家排行榜:膨胀型 / 非膨胀型 / 厚型 / 薄型钢结构防火涂料优质企业最新推荐
  • 2025年GEO品牌推荐榜单:AI技术驱动的行业革新者
  • 2025年GEO品牌推荐排行榜TOP10:AI技术驱动的行业新格局
  • 2025 年南昌装修设计公司推荐:宿然设计,非营销型技术工作室,专注落地还原,提供全国纯设计与江西全案服务
  • 2025 年板材源头厂家最新推荐排行榜:聚焦 ENF 级环保与高品质,精选 6 家实力企业助您轻松选
  • 中部地区-河南湖北湖南
  • Hash与布隆过滤器
  • 2025 年最新推荐防火涂料厂家排行榜:涵盖膨胀型、非膨胀型、室内外及超薄厚型钢结构防火涂料,助选优质产品