【题解】CF79D Password

考场上背包骗了 45 pts (雾 。

考点:状压 + 差分 + 最短路

说实话第一步转移我没太看懂。(但是不影响做法

可以把题目要求变换的位置看成 1 。

问题转化为若干次操作使得原序列全为 0 。

求出差分数组,问题转化为对于新的差分序列,每次将两个位置的状态取反。

如果当前为 1 的点有奇数个的话直接输出无解。

否则容易想到两两匹配。这里可以 o(20nl) 预处理最短路。

最后观察到差分后为 1 的点的个数 <=20 ,直接状压即可。

#include<bits/stdc++.h> #define ll long long #define inf 0x3f3f3f3f #define fi first #define se second #define pii pair<int,int> using namespace std; const int Maxn=1e5+5; const int Maxm=1<<20; int n,k,l,a[Maxn],b[Maxn],c[Maxn],g[20][20],dis[Maxn],d[Maxn],rk[Maxn],dp[Maxm],m; vector<int> vec[Maxn]; queue<int> q; signed main() { freopen("perish.in","r",stdin); freopen("perish.out","w",stdout); memset(dp,0x3f,sizeof dp); memset(g,0x3f,sizeof g); memset(rk,-1,sizeof rk); dp[0]=0; scanf("%d%d%d",&n,&k,&l); for(int i=1;i<=k;i++) { int x; scanf("%d",&x); a[x]=1; } for(int i=1;i<=n+1;i++) { c[i]=a[i]^a[i-1]; if(c[i]) rk[i]=m,d[m++]=i; } for(int i=1;i<=l;i++) { scanf("%d",&b[i]); for(int j=1;j<=n-b[i]+1;j++) { vec[j].push_back(j+b[i]); vec[j+b[i]].push_back(j); } } for(int i=0;i<=m;i++) { for(int j=1;j<=n+1;j++) dis[j]=inf; q.push(d[i]); dis[d[i]]=0; while(q.size()) { int x=q.front(); q.pop(); for(auto y:vec[x]) { if(dis[y]>dis[x]+1) { dis[y]=dis[x]+1; q.push(y); if(~rk[y]) g[i][rk[y]]=dis[y]; } } } } for(int i=1;i<1<<m;i++) { int c[20],cnt=0; for(int j=0;j<m;j++) { if(i>>j&1) { c[cnt++]=j; } } if(cnt&1) continue; for(int j=1;j<cnt;j++) { dp[i]=min(dp[i],dp[i-(1<<c[0])-(1<<c[j])]+g[c[0]][c[j]]); } } if(dp[(1<<m)-1]==inf) { printf("-1"); } else { printf("%d",dp[(1<<m)-1]); } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530248.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(9)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示