CF79D Password

CF79D Password 

挺巧妙的题

看起来无从下手

k很小,先不管

把最终需要亮的看做1,不需要的看做0

要把全0序列,变成有至多10个1的01序列

不妨考虑把01序列变回全0序列(这样容易思考)

区间取反?

差分变成两个单点取反!

特殊加入n+1位置,这样便于取反

 

首先,两个0取反一定不优,可以用01取反和11取反来得到相同的效果

01取反,等价于1走到0,11取反,等价于两个1消掉。

不断两个位置进行取反,一定是为了最后把两个1消掉!

也就是,其实是两个1的匹配

 

1一共只有20个

最短路建图,f[i][j]表示i和j匹配的最小代价,也即最短路

一个问题是:不会影响其他位置的值吗?

发现这个最短路的边,除了起点终点,都恰好xor两次(虽然这样并不优)!不会影响其他的位置的值!

BFS求最短路

然后Dp即可

枚举和S的lowbit进行匹配的点

O(20*2^20)

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
#define numb (ch^'0')
#define pb push_back
#define solid const auto &
#define enter cout<<endl
#define pii pair<int,int>
using namespace std;
typedef long long ll;
template<class T>il void rd(T &x){
    char ch;x=0;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x);}
template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');}
namespace Modulo{
const int mod=998244353;
int ad(int x,int y){return (x+y)>=mod?x+y-mod:x+y;}
void inc(int &x,int y){x=ad(x,y);}
int mul(int x,int y){return (ll)x*y%mod;}
void inc2(int &x,int y){x=mul(x,y);}
int qm(int x,int y=mod-2){int ret=1;while(y){if(y&1) ret=mul(x,ret);x=mul(x,x);y>>=1;}return ret;}
}
//using namespace Modulo;
namespace Miracle{
const int N=10000+5;
const int M=105;
const int K=22;
const int inf=0x3f3f3f3f;
int n,k,m;
int pos[K],dis[N],cnt;
int f[K][K];
int a[N],b[N];
int dp[(1<<20)+23];
int q[N],l,r;
void bfs(int st){
    memset(dis,0x3f,sizeof dis);
    dis[pos[st]]=0;
    l=1,r=0;
    q[++r]=pos[st];
    while(l<=r){
        int x=q[l++];
        for(reg i=1;i<=m;++i){
            int to=x+b[i];
            if(to<=n+1&&dis[to]>dis[x]+1){
                dis[to]=dis[x]+1;
                q[++r]=to;
            }
            to=x-b[i];
            if(to>0&&dis[to]>dis[x]+1){
                dis[to]=dis[x]+1;
                q[++r]=to;
            }
        }
    }
    for(reg i=1;i<=cnt;++i){
        f[st][i]=dis[pos[i]];
    }
}
int num(int p){
    int sz=__builtin_ctz(p);
    return sz+1;
}
int main(){
    rd(n);rd(k);rd(m);
    for(reg i=1;i<=k;++i){
        int x;rd(x);
        a[x]=1;
    }
    for(reg i=1;i<=m;++i){
        rd(b[i]);
    }
    for(reg i=n+1;i>=1;--i){
        a[i]^=a[i-1];
        if(a[i]==1) pos[++cnt]=i;
    }
    // prt(a,1,n+1);
    // prt(pos,1,cnt);
    for(reg i=1;i<=cnt;++i){
        // cout<<" bfs i------------ "<<i<<endl;
        bfs(i);
        // prt(f[i],1,cnt);
    }
    memset(dp,0x3f,sizeof dp);
    dp[0]=0;
    for(reg s=1;s<(1<<cnt);++s){
        int sz=__builtin_popcount(s);
        if((sz&1)) continue;
        // cout<<" ss "<<s<<endl;
        int t=s&(-s);
        for(reg tmp=s^t,p=tmp&(-tmp);tmp;tmp=tmp^p,p=tmp&(-tmp)){
            // cout<<" t "<<t<<" num(t) "<<num(t)<<" p "<<p<<" num(p) "<<num(p)<<" fan "<<dp[s^t^p]<<endl;
            dp[s]=min(dp[s],dp[s^t^p]+f[num(t)][num(p)]);
        }
    }
    // prt(dp,0,(1<<cnt)-1);
    if(dp[(1<<cnt)-1]==inf){
        puts("-1");
    }else{
        printf("%d\n",dp[(1<<cnt)-1]);
    }
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
*/

 

posted @ 2019-05-27 20:55  *Miracle*  阅读(258)  评论(0编辑  收藏  举报