码迷,mamicode.com
首页 > 其他好文 > 详细

CF79D 【Password】

时间:2020-02-14 16:56:02      阅读:103      评论:0      收藏:0      [点我收藏+]

标签:增加   决定   sha   1的个数   some   过程   tput   section   rom   

原题描述
D. Password
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Finally Fox Ciel arrived in front of her castle!

She have to type a password to enter her castle. An input device attached to her castle is a bit unusual.

The input device is a 1 × n rectangle divided into n square panels. They are numbered 1 to n from left to right. Each panel has a state either ON or OFF. Initially all panels are in the OFF state. She can enter her castle if and only if x1-th, x2-th, ..., xk-th panels are in the ON state and other panels are in the OFF state.

She is given an array a1, ..., al. In each move, she can perform the following operation: choose an index i (1 ≤ i ≤ l), choose consecutive ai panels, and flip the states of those panels (i.e. ON → OFF, OFF → ON).

Unfortunately she forgets how to type the password with only above operations. Determine the minimal number of operations required to enter her castle.

Input

The first line contains three integers nk and l (1 ≤ n ≤ 10000, 1 ≤ k ≤ 10, 1 ≤ l ≤ 100), separated by single spaces.

The second line contains k integers x1, ..., xk (1 ≤ x1 < x2 < ... < xk ≤ n), separated by single spaces.

The third line contains l integers a1, ..., al (1 ≤ ai ≤ n), separated by single spaces. It is possible that some elements of the array ai are equal value.

Output

Print the minimal number of moves required to type the password. If it‘s impossible, print -1.

Examples
input
10 8 2
1 2 3 5 6 7 8 9
3 5
output
2
input
3 2 1
1 2
3
output
-1
Note

One possible way to type the password in the first example is following: In the first move, choose 1st, 2nd, 3rd panels and flip those panels. In the second move, choose 5th, 6th, 7th, 8th, 9th panels and flip those panels.

 翻译题面:

问题 D: 密码锁(password)

题目描述

hzwer有一把密码锁,由N个开关组成。一开始的时候,所有开关都是关上的。当且仅当开关x1,x2,x3,...xk为开,其他开关为关时,密码锁才会打开。

他可以进行M种的操作,每种操作有一个size[i],表示,假如他选择了第i种的操作的话,他可以任意选择连续的size[i]个格子,把它们全部取反。(注意,由于黄金大神非常的神,所以操作次数可以无限>_<)

本来这是一个无关紧要的问题,但是,黄金大神不小心他的钱丢进去了,没有的钱他哪里能逃过被chenzeyu97 NTR的命运?>_<  于是,他为了虐爆czy,也为了去泡更多的妹子,决定打开这把锁。但是他那么神的人根本不屑这种”水题”。于是,他找到了你。

你的任务很简单,求出最少需要多少步才能打开密码锁,或者如果无解的话,请输出-1。

输入

第1行,三个正整数N,K,M,如题目所述。

第2行,K个正整数,表示开关x1,x2,x3..xk必须为开,保证x两两不同。

第三行,M个正整数,表示size[i],size[]可能有重复元素。

输出

输出答案,无解输出-1。

【样例输入2】

3 2 1

1 2

3

【样例输出2】

-1

【数据规模】

对于50%的数据,1≤N≤20,1≤k≤5,1≤m≤3;

对于另外20%的数据,1≤N≤10000,1≤k≤5,1≤m≤30;

对于100%的数据,1≤N≤10000,1≤k≤10,1≤m≤100。

样例输入 Copy

10 8 2
1 2 3 5 6 7 8 9
3 5

样例输出 Copy

2

题解:

标签:状压+bfs+dp

虽然题目中说的的是区间修改,但是我们可以通过考虑它的差分序列,使得要修改的位置个数变成2个。

我们应该很容易发现,这题可以使用逆向思维,只要求出最少的修改,使得原序列变成全0就可以了。

so,对原序列进行差分,那么每次修改就是要你对i号位置和i+size[]模2意义下的加1。容易看出:差分后的序列中,数值为1的个数是不会超过2k个,即不会超过20个。

考虑每次对i和i+x改动的过程,如果原序列中,i号位置和i+x号位置都是0的话,没有必要进行改动。所以任意时刻,数值为1的位置个数是不会增加的。so,我们可以把每一个的1看成一个的石子,那么每次我们可以把石子往某个方向移动size[]步,如果移动之后的位置存在石子的话,就相互抵消掉了。

至此,不难看出,石子之间的关系肯定是一个匹配的关系,否则就没有抵消这种说法。我们先bfs一遍所有是1的点,求出Dist[i][j]表示,石子i要走到石子j的位置,至少需要移动多少步,这一部分的复杂度是O(2kmn)。

现在问题转化为有一个大小不超过20的完全图,我们想要求它的最小权最大匹配。

可以用状压DP,设f[S]表示集合S的最小划分代价,每次选出最小的元素作为匹配元素之一,枚举另一个元素即可。

上代码

#include<bits/stdc++.h>
using namespace std;
const int M=1e4+5,INF=1<<29;
int n,k,m,cnt;
int a[M],num[M],Dist[25][25],size[M];
int visited[M],Distance[M],f[1<<25];
queue<int> q;
void bfs(int x,int id) 
{
    memset(visited,0,sizeof(visited));
    memset(Distance,0x3f3f3f3f,sizeof Distance);
    q.push(x);
	visited[x]=1; Distance[x]=0;
    while(!q.empty()) 
	{
        x=q.front();q.pop();
        for(int i=1; i<=m; i++)
		{
			int tmp=size[i];
            if((x+tmp)<=n && !visited[x+tmp]) 
			{
                visited[x+tmp]=1;
				Distance[x+tmp]=Distance[x]+1;
				q.push(x+tmp);
            }
            if((x-tmp)>=1 && !visited[x-tmp]) 
			{
                visited[x-tmp]=1;
				Distance[x-tmp]=Distance[x]+1;
				q.push(x-tmp);
            }
        }
    }
    for(int i=1; i<=cnt; i++)
	{
        if(visited[num[i]]) Dist[id][i]=Distance[num[i]];
        else Dist[id][i]=INF;
    } 
}
void dp()
{
	for(int i=1; i<(1<<cnt); i++) f[i]=INF;
    for(int i=0,j; i<(1<<cnt); i++)
	{
        for(int k=1; k<=cnt; k++)
		    if((1<<k-1)&i) 
			{
			    j=k;
				break;
			}
        for(int k=1; k<=cnt; k++) 
		    if((1<<k-1)&i) 
                f[i]=min(f[i],f[i^(1<<j-1)^(1<<k-1)]+Dist[j][k]);
    }
}
int main() 
{
    scanf("%d%d%d",&n,&k,&m);
    for(int i=1; i<=k; i++)  
    {
    	int x; scanf("%d",&x);
    	a[x]=1;
	}
    for(int i=1; i<=m; i++) scanf("%d",&size[i]);
    for(int i=++n; i>=1; i--) a[i]^=a[i-1];
    for(int i=1; i<=n; i++) 
	    if(a[i]) 
		{
			a[i]=++cnt;
			num[cnt]=i;
		}
    for(int i=1; i<=n; i++) 
	    if(a[i]) bfs(i,a[i]);
	dp(); 
    if(f[(1<<cnt)-1]==INF) puts("-1");
    else printf("%d\n",f[(1<<cnt)-1]);
    return 0;
}

  2020-02-1415:38:47

CF79D 【Password】

标签:增加   决定   sha   1的个数   some   过程   tput   section   rom   

原文地址:https://www.cnblogs.com/crh1272336175/p/12307648.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!