CSP-S 2025 个人解法
I_am_Accepted
·
·
题解
暂醒复寐
题解
社团招新 / club
尝试让所有人都选满意度最高的部门。如果出现了超员的部门,求每个在该部门的人转至第二喜欢的部门的代价。将代价排序并取最小的那些即可。调整后一定不会出现超员的部门,因为不可能有第二个人数超过 n/2 的部门。
道路修复 / road
$O(2^knk(\alpha(n)+\log k))$ 过了,嘻嘻。
DFS 出所有乡镇是否启用,维护当前点集的 MST,每次将 $O(n)$ 的边集归并与 Kruskal,复杂度 $O(2^kn\alpha(n))$。
每次归并的两个边集为 $\delta(x)$ 和 $E(G)\backslash\delta(x)$,有良好的性质。遂不用并查集,直接连通块打标记即可,具体见代码,复杂度 $O(2^kn)$。
### 谐音替换 / replace
找到规则/询问最左和最右的修改位置,按照中间这段从啥改到啥分类(使用字符串哈希)。接下来我们只关注同一类中的规则/询问。
将规则的前缀后缀分别建 trie 树(前缀要反转)。设规则的前缀后缀 pair 集合为 $S$。每个询问转化为 $x,y$ 分别是第一/第二棵树上的节点,查询 $|\{(x'\text{ is anc of }x)\land(y'\text{ is anc of }y)|(x',y')\in S\}|$。将询问离线下来,DFS 第一棵树,查询第二棵树点到根的链和。由于链长之和有保证,所以这部分复杂度线性。
### 员工招聘 / employ
$f_{i,j,k}$ 表示前 $i$ 个面试位置,在 $\mathtt{1}$ 处放了 $j$ 个应聘人,有 $k$ 个通过面试的方案数。
若一位应聘人通过面试,则对其耐心的限制为大于某个值。我们将这些限制容斥成【不限制】与【限制耐心不超过某个值】。
此 DP 只在 $\mathtt{1}$ 处转移(从上一个 $\mathtt{1}$ 转移过来,忽略中间的 $\mathtt{0}$),将第一维 $i$ 滚动掉。
$$
\begin{aligned}
f'_{j,k+1}
&\longleftarrow f_{j,k}
&\quad\text{(approved with no constraint)}
\\
f'_{j+1,k+1}
&\longleftarrow (-1)\times f_{j,k}\times (\text{cnt}_{\le i-1-k}-j)
&\quad\text{(approved with an I-E constraint)}
\\
f'_{j+1,k}
&\longleftarrow f_{j,k}\times (\text{cnt}_{\le i-1-k}-j)
&\quad\text{(rejected)}
\end{aligned}
$$
最后将 DP 值乘上 $(n-j)!$ 即为所求。
## 代码
### T1
```cpp
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,a[N][3],mx[N],cnt[3];
void work(){
cin>>n;
for(int i=1;i<=n;i++) for(int j=0;j<3;j++) cin>>a[i][j];
for(int j=0;j<3;j++) cnt[j]=0;
int sum=0;
for(int i=1;i<=n;i++){
cnt[mx[i]=max_element(a[i],a[i]+3)-a[i]]++;
sum+=a[i][mx[i]];
}
int w=-1;
for(int j=0;j<3;j++) if(cnt[j]*2>n) w=j;
if(w!=-1){
int del=cnt[w]-n/2;
vector<int> s;
for(int i=1;i<=n;i++) if(mx[i]==w){
sort(a[i],a[i]+3);
s.emplace_back(a[i][2]-a[i][1]);
}
sort(s.begin(),s.end());
for(int i=0;i<del;i++) sum-=s[i];
}
cout<<sum<<"\n";
}
signed main(){ios::sync_with_stdio(false);
int T;cin>>T;
while(T--)work();
return 0;
}
```
### T2
```cpp
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+30;
struct edge{
int u,v,w;
edge(int _u,int _v,int _w):u(_u),v(_v),w(_w){}
edge(){}
friend bool operator<(const edge&x,const edge&y){
return x.w<y.w;
}
};
vector<edge> dis[10];
vector<int> e[N];
int n,m,cost[10],f[N];
bool vis[N];
long long ans=1e18;
inline int gf(int x){return x==f[x]?x:f[x]=gf(f[x]);}
bool link(int x,int y){
x=gf(x),y=gf(y);
if(x==y) return false;
f[x]=y;
return true;
}
void paint(int x){
if(vis[x]) return ;
vis[x]=true;
for(int i:e[x]) paint(i);
}
vector<edge> shrink(vector<edge> edges,int root){
vector<edge> res;
for(int i=1;i<=n+m;i++) vis[i]=false,e[i].clear();
for(auto i:edges){
if(i.u==root || i.v==root){
int x=i.u^i.v^root;
if(!vis[x]){
res.emplace_back(i);
paint(x);
}
}else{
int x=i.u;
int y=i.v;
e[x].emplace_back(y);
e[y].emplace_back(x);
if(!vis[x]&&!vis[y]){
res.emplace_back(i);
}else if(vis[x]&&!vis[y]){
res.emplace_back(i);
paint(y);
}else if(!vis[x]&&vis[y]){
res.emplace_back(i);
paint(x);
}
}
}
return res;
}
void dfs(int w,vector<edge> edges,long long co){
if(w==m){
for(auto i:edges) co+=i.w;
ans=min(ans,co);
return ;
}
dfs(w+1,edges,co);
vector<edge> edges_new;
merge(edges.begin(), edges.end(),
dis[w].begin(), dis[w].end(),
back_inserter(edges_new));
edges_new=shrink(edges_new,n+1+w);
dfs(w+1,edges_new,co+cost[w]);
}
signed main(){ios::sync_with_stdio(false);
cin>>n>>m;
vector<edge> edges,edges_new;
edges.resize(m);
cin>>m;
for(auto&[u,v,w]:edges){
cin>>u>>v>>w;
}
sort(edges.begin(),edges.end());
iota(f+1,f+1+n,1);
for(auto[u,v,w]:edges){
if(link(u,v)){
edges_new.emplace_back(u,v,w);
}
}
for(int i=0;i<m;i++){
cin>>cost[i];
for(int j=1;j<=n;j++){
int x;cin>>x;
dis[i].emplace_back(n+1+i,j,x);
}
sort(dis[i].begin(),dis[i].end());
}
dfs(0,edges_new,0);
cout<<ans<<"\n";
return 0;
}
```
### T3
```cpp
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10,M=5e6+10;
const long long P=((long long)1e18)+3,base=998244353;
int n,m,ans[N];
map<long long,
pair<
vector<pair<string,string>>,
vector<pair<pair<string,string>,int>>
>
> mp;
struct trie{
int ch[M][26],f[M],tot;
void clear(){
tot=0;
nnd();
}
int nnd(){
tot++;
f[tot]=0;
for(int i=0;i<26;i++) ch[tot][i]=0;
return tot;
}
int&operator()(int x,char w){
return ch[x][w-'a'];
}
int operator()(int x){
return f[x];
}
int insert(string x){
int rt=1;
for(auto w:x){
int&res=(*this)(rt,w);
if(!res) res=nnd(),f[res]=rt;
rt=res;
}
return rt;
}
int insert2(string x){
int rt=1;
for(auto w:x){
int&res=(*this)(rt,w);
if(!res) break;
rt=res;
}
return rt;
}
void traverse(function<void(int)> in,function<void(int)> out,int x=1){
in(x);
for(int i=0;i<26;i++) if(ch[x][i]) traverse(in,out,ch[x][i]);
out(x);
}
}F,G;
vector<int> hang[M];
vector<pair<int,int>> hang2[M];
int cnt[M];
long long hsh(string x){
long long res=0;
for(auto i:x) res=((__int128)res*base+i)%P;
return res;
}
pair<long long,pair<string,string>> get_diff(string x,string y){
int l=0,r=x.size()-1;
while(x[l]==y[l]) l++;
while(x[r]==y[r]) r--;
string tmp=x.substr(0,l);
reverse(tmp.begin(),tmp.end());
return make_pair(hsh(x.substr(l,r-l+1)+y.substr(l,r-l+1)),make_pair(tmp,x.substr(r+1,x.size()-r-1)));
}
signed main(){ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++){
string x,y;
cin>>x>>y;
if(x!=y){
auto[xx,yy]=get_diff(x,y);
mp[xx].first.emplace_back(yy);
}
}
for(int i=1;i<=m;i++){
string x,y;
cin>>x>>y;
if(x.size()==y.size()){
auto[xx,yy]=get_diff(x,y);
mp[xx].second.emplace_back(yy,i);
}
}
for(const auto&[key,value]:mp){
const auto&[rules,queries]=value;
for(int i=1;i<=F.tot;i++) hang[i].clear(),hang2[i].clear();
for(int i=1;i<=G.tot;i++) cnt[i]=0;
F.clear(),G.clear();
for(const auto&[i,j]:rules){
int y=G.insert(j);
hang[F.insert(i)].emplace_back(y);
}
for(const auto&[i,k]:queries){
int x=F.insert2(i.first);
int y=G.insert2(i.second);
hang2[x].emplace_back(y,k);
}
F.traverse(
[&](int x){
for(int i:hang[x]){
cnt[i]++;
}
for(auto[i,j]:hang2[x]){
while(i){
ans[j]+=cnt[i];
i=G(i);
}
}
},
[&](int x){
for(int i:hang[x]){
cnt[i]--;
}
}
);
}
for(int i=1;i<=m;i++){
cout<<ans[i]<<"\n";
}
return 0;
}
```
### T4
```cpp
#include<bits/stdc++.h>
using namespace std;
const int N=504,P=998244353;
int n,m,b[N],f[N][N],g[N][N],cnt[N],fac[N];
char a[N];
signed main(){ios::sync_with_stdio(false);
cin>>n>>m;
fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=(long long)fac[i-1]*i%P;
cin>>(a+1);
for(int i=1;i<=n;i++) cin>>b[i],cnt[b[i]]++;
for(int i=1;i<=n;i++) cnt[i]+=cnt[i-1];
f[0][0]=1;
for(int i=1;i<=n;i++){
if(a[i]=='1'){
for(int j=0;j<=n;j++){
for(int k=0;k<=n;k++){
g[j][k]=0;
}
}
for(int j=0;j<=n;j++){
for(int k=0;k<=n;k++){
if(f[j][k]!=0){
(g[j][k+1]+=f[j][k])%=P;
(g[j+1][k+1]+=P-(long long)f[j][k]*max(0,cnt[i-1-k]-j)%P)%=P;
(g[j+1][k]+=(long long)f[j][k]*max(0,cnt[i-1-k]-j)%P)%=P;
}
}
}
for(int j=0;j<=n;j++){
for(int k=0;k<=n;k++){
f[j][k]=g[j][k];
}
}
}
}
int ans=0;
for(int j=0;j<=n;j++){
for(int k=m;k<=n;k++){
(ans+=(long long)f[j][k]*fac[n-j]%P)%=P;
}
}
cout<<ans<<"\n";
return 0;
}
```