AcWing 1960. 闪烁(状态压缩+枚举)

Posted MangataTS

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AcWing 1960. 闪烁(状态压缩+枚举)相关的知识,希望对你有一定的参考价值。

题目链接

https://www.acwing.com/problem/content/1962/

思路

这题如果用一个数组的话是会炸空间的,所以我们采用状态压缩,因为每个灯的状态只有0和1,那么我们直接定义一个状态表示的是当前的状态,然后由于这个长度是16,所以我们最多能有 2 16 2^16 216种开关灯的状态,我们直接用一个int即可,然后我们发现关于灯的开关状态其实就是那当前这一位和前面一位(环形)做一个异或操作,由于数据一定会出现循环,所以一旦我们发现了循环的地方就直接取模然后继续往后走余下的步数即可。详情请看代码

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mod 1000000009
ll ksm(ll a,ll b) 
	ll ans = 1;
	for(;b;b>>=1LL) 
		if(b & 1) ans = ans * a % mod;
		a = a * a % mod;
	
	return ans;


ll lowbit(ll x)return -x & x;

const int N = 2e6+10;

int n;
ll m;
int vis[N];

int update(int state)//更新状态
	int ans = 0;
	for(int i = 0;i < n; ++i) 
		int j = (i - 1 + n) % n;
		int l = state >> i & 1;
		int r = state >> j & 1;
		ans |= (l ^ r) << i;
	
	return ans;

void print(int state)//输出每一位
	for(int i = 0;i < n; ++i) 
		cout<<(state>>i & 1)<<endl;
	


int main()

	cin>>n>>m;
	int state;
	for(int i = 0;i < n; ++i) 
		int k;
		cin>>k;
		state |= k<<i;//初始初始状态
	
	memset(vis,-1,sizeof vis);//初始化
	vis[state] = 0;
	for(int i = 1;1;i++)
		state = update(state);//更新当前状态
		if(i == m)//如果直接找到了第m个状态直接输出
			print(state);
			break;
		
		else if(vis[state] == -1) //如果没有记录该状态,那么记录出现在第几次
			vis[state] = i;
		
		else //如果找到了一个循环节
			int len = i - vis[state];
			int leave = (m-i) % len;//剩下的步数
			while(leave--) state = update(state);
			print(state);
			return 0;
		
	
	
	return 0;

以上是关于AcWing 1960. 闪烁(状态压缩+枚举)的主要内容,如果未能解决你的问题,请参考以下文章

Acwing292. 炮兵阵地(网格型状态压缩dp)

AcWing 291. 蒙德里安的梦想(状态压缩dp模板)

AcWing 291. 蒙德里安的梦想(状态压缩dp模板)

Acwing292. 炮兵阵地(网格型状态压缩dp)

AcWing 164. 可达性统计 拓扑排序+状态压缩

《算法竞赛进阶指南》0x56状态压缩DP AcWing529 宝藏