CF79D Password

题目链接

题意:给定长度为n的0/1序列,初始值都为0。你每次可以在给定的l个长度中的(a_i)并将序列中长度为(a_i)的部分取反。使得最终状态为(x_1)~(x_k),求最少取反次数。

分析:看到这种区间整体变化的题,我们应该直觉想到差分(也可能想到线段树

先求出差分后的数组,然后每次操作相当于对距离为(a_i)的两点取反。

我们可以用类似求最短路的方法求出取反i,j位的最小操作次数。

因为最后为1的位置 (leq) 10,所以操作的次数 (leq) 20。

所以就可以大力状压了,方程见代码。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int dp[1<<20], num[1<<20], low[1<<20], f[10005], dis[10005], mn[22][22], len[105], cnt[22];
int n, k, l, tot=0;
queue<int> q;

inline int read()
{
    int x=0,f=1; char ch=getchar();
    for (; ch<'0' || ch>'9'; ch=getchar()) if (ch=='-') f=-1;
    for (; ch>='0' && ch<='9'; ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}

void Get_Shortest_Path(int rt)
{
    memset(dis, 0x3f, sizeof(dis)); dis[cnt[rt]]=0;
    q.push(cnt[rt]);
    while (!q.empty())
    {
        int u=q.front(); q.pop();
        for (int i=1; i<=l; i++)
        {
            if (u+len[i]<=n+1 && dis[u+len[i]]>dis[u]+1)
                {dis[u+len[i]]=dis[u]+1; q.push(u+len[i]);}
            if (u-len[i]>0 && dis[u-len[i]]>dis[u]+1)
                {dis[u-len[i]]=dis[u]+1; q.push(u-len[i]);}
        }
    }
    for (int i=1; i<=tot; i++) mn[rt][i]=dis[cnt[i]];
}

int main()
{
    n=read(); k=read(); l=read();
    for (int i=1; i<=k; i++) {int x=read(); f[x]=1;}
    for (int i=1; i<=n+1; i++) if (f[i]^f[i-1]) cnt[++tot]=i;//差分
    for (int i=1; i<=l; i++) len[i]=read();
    for (int i=1; i<=tot; i++) Get_Shortest_Path(i);//预处理取反i,j位的最小操作次数
    low[1]=0; for (int i=2; i<(1<<tot); i++) low[i]=low[i>>1]+1;//预处理log_2
    for (int i=1; i<(1<<tot); i++) num[i]=num[i-(i&-i)]+1;//预处理二进制位数
    memset(dp, 0x3f, sizeof(dp)); dp[0]=0;
    for (int i=0; i<(1<<tot); i++)
    {
        if (num[i]&1) continue;
        int j=((1<<tot)-1)^i; j=low[j&-j]+1;
        for (int k=j+1; k<=tot; k++)
            dp[i|(1<<(j-1))|(1<<(k-1))]=
                min(dp[i|(1<<(j-1))|(1<<(k-1))],
                    dp[i]+mn[j][k]);
    }//状压
    printf("%d
",dp[(1<<tot)-1]==inf?-1:dp[(1<<tot)-1]);
    return 0;
}

我才不会告诉你们这题有双倍经验的

原文地址:https://www.cnblogs.com/ACMSN/p/10147396.html