【Codeforces】 CF79D Password

题目链接

CF方向
Luogu方向

题目解法

看到区间异或,一个经典的套路是做差分,我们即在 l l l 处异或一次,在 r + 1 r+1 r+1 处异或一次,然后前缀和起来

于是我们可以将问题转化成:有一个序列初始全 0 0 0,每次可以把相隔 a i a_i ai 的数都 ⊕ 1 \oplus 1 ⊕1,求最少将其变成一个状态的步数

考虑 k k k 的范围很小,所以为 1 1 1 的地方一共只有 2 k 2k 2k 个

这里有一个非常重要的 t r i c k trick trick:在异或操作中,如果需要把 x , y x,y x,y 同时异或 1 1 1,其他不变,每次可以同时修改相隔 a i a_i ai 的位置的异或值,那么这个问题等价于建出图来从 x x x 到 y y y 的最短路

然后发现直接状压跑最短路即可,时间复杂度 O ( 2 k k 2 ) O(2^kk^2) O(2kk2)

不难优化成 O ( 2 k k ) O(2^kk) O(2kk),但我直接 998 m s 998ms 998ms 用 O ( 2 k k 2 ) O(2^kk^2) O(2kk2) 的做法艹过去了,就懒得改了
O ( 2 k k 2 ) O(2^kk^2) O(2kk2) 的代码:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N=10100,M=2000100;
int n,m,k,a[110],x[30],dis[N];
int f[(1<<20)+100],D[30][30];
int e[M],ne[M],h[N],idx;
inline int read(){
    int FF=0,RR=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
    for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
    return FF*RR;
}
queue<int> que;
void bfs(int S){
    memset(dis,0x3f,sizeof(dis));
    que.push(S),dis[S]=0;
    while(!que.empty()){
        int u=que.front();que.pop();
        for(int i=h[u];~i;i=ne[i]) if(dis[u]+1<dis[e[i]])
            dis[e[i]]=dis[u]+1,que.push(e[i]);
    }
}
void add(int x,int y){ e[idx]=y,ne[idx]=h[x],h[x]=idx++;}
int main(){
    n=read(),k=read(),m=read();
    for(int i=0;i<k;i++) x[i]=read();
    for(int i=1;i<=m;i++) a[i]=read();
    for(int i=0;i<k;i++) x[i+k]=x[i]+1;
    memset(h,-1,sizeof(h));
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n-a[i]+1;j++)
            add(j,j+a[i]),add(j+a[i],j);
    for(int i=0;i<k<<1;i++){
        bfs(x[i]);
        for(int j=0;j<k<<1;j++) D[i][j]=dis[x[j]];
    }
    memset(f,0x3f,sizeof(f));
    f[0]=0;
    for(int S=0;S<1<<(k<<1);S++)
        for(int i=0;i<k<<1;i++) if(S>>i&1)
            for(int j=0;j<k<<1;j++) if(S>>j&1) if(i!=j)
                f[S]=min(f[S],f[S^(1<<i)^(1<<j)]+D[i][j]);
    printf("%d\n",f[(1<<(k<<1))-1]>1e9?-1:f[(1<<(k<<1))-1]);
    fprintf(stderr,"%d ms\n",int(1e3*clock()/CLOCKS_PER_SEC));
    return 0;
}
相关推荐
MZWeiei1 小时前
PTA:运用顺序表实现多项式相加
算法
GISer_Jing2 小时前
Javascript排序算法(冒泡排序、快速排序、选择排序、堆排序、插入排序、希尔排序)详解
javascript·算法·排序算法
cookies_s_s2 小时前
Linux--进程(进程虚拟地址空间、页表、进程控制、实现简易shell)
linux·运维·服务器·数据结构·c++·算法·哈希算法
不想编程小谭2 小时前
力扣LeetCode: 2506 统计相似字符串对的数目
c++·算法·leetcode
水蓝烟雨2 小时前
[HOT 100] 2187. 完成旅途的最少时间
算法·hot 100
菜鸟一枚在这4 小时前
深度解析建造者模式:复杂对象构建的优雅之道
java·开发语言·算法
gyeolhada4 小时前
2025蓝桥杯JAVA编程题练习Day5
java·数据结构·算法·蓝桥杯
阿巴~阿巴~4 小时前
多源 BFS 算法详解:从原理到实现,高效解决多源最短路问题
开发语言·数据结构·c++·算法·宽度优先
给bug两拳4 小时前
Day9 25/2/22 SAT
算法
_Itachi__5 小时前
LeetCode 热题 100 73. 矩阵置零
算法·leetcode·矩阵