洛古模拟赛--星空

这题很劲啊

首先令b[i]=a[i]^a[i+1];

这样对a进行的区间操作即为对b的单点修改

目的变成了将b进行一些长度两端点的反转,使其全为0

考虑一个1,一个0,可以看做1移动到了0的位置,两个1呢,则可以看成撞到一起消去了

那么可以bfs处理出每两个1间的最短路,状压dp转移就好了

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define N 40050
 7 using namespace std;
 8 int n,K,m;
 9 int a[N],b[N],c[N],f[20][20],g[1<<20];
10 int pos[20],tot;
11 int bit[20];
12 int vis[N],dis[N];
13 int q[N],head,tail;
14 int main(){
15     bit[0]=1;
16     for(int i=1;i<=18;i++)bit[i]=bit[i-1]<<1;
17     scanf("%d%d%d",&n,&K,&m);
18     for(int i=1,x;i<=K;i++)scanf("%d",&x),a[x]=1;
19     for(int i=0;i<=n;i++)b[i]=a[i]^a[i+1];
20     for(int i=1;i<=m;i++)scanf("%d",&c[i]);
21     for(int i=0;i<=n;i++)if(b[i])pos[++tot]=i;
22     for(int i=1;i<=tot;i++){
23         memset(vis,0,sizeof vis);
24         memset(dis,0x3f,sizeof dis);
25         head=tail=1;q[1]=pos[i];vis[pos[i]]=1;dis[pos[i]]=0;
26         while(head<=tail){
27             int x=q[head++];
28             for(int i=1;i<=m;i++){
29                 if(x-c[i]>=0&&!vis[x-c[i]]){vis[x-c[i]]=1;dis[x-c[i]]=dis[x]+1;q[++tail]=x-c[i];}
30                 if(x+c[i]<=n&&!vis[x+c[i]]){vis[x+c[i]]=1;dis[x+c[i]]=dis[x]+1;q[++tail]=x+c[i];}
31             }
32         }
33         for(int j=1;j<=tot;j++)f[i][j]=dis[pos[j]];
34     }
35     memset(g,0x3f,sizeof g);
36     g[0]=0;
37     for(int i=0;i<bit[tot];i++){
38         for(int j=1;j<=tot;j++)if(!(i&bit[j-1]))
39             for(int k=1;k<=tot;k++)if(k!=j&&(!(i&bit[k-1])))
40                 g[i|bit[j-1]|bit[k-1]]=min(g[i|bit[j-1]|bit[k-1]],g[i]+f[j][k]);
41     }
42     printf("%d
",g[bit[tot]-1]);
43     return 0;
44 }
starlit
原文地址:https://www.cnblogs.com/Ren-Ivan/p/7791562.html