首页 > 其他分享 >题解 【[USACO23JAN] Lights Off G】

题解 【[USACO23JAN] Lights Off G】

时间:2023-02-01 10:46:46浏览次数:42  
标签:cnt Off int 题解 len 异或 USACO23JAN 操作 include

problem

给两个长为 \(n\) 的 0/1 字符串 \(S,T\),进行如下操作 \(cnt\) 次:

  • 自行选定 \(0\leq x<n\),使得 \(T_x\) 异或一。
  • 将 \(S\) 异或上 \(T\)。
  • 将 \(T\) 的最后一位移动到最前面,即如 \(0123\) 变成 \(3012\)。

最小化 \(cnt\) 使得 \(S\) 全为零。\(n\leq 20\),多测 \(10^5\) 组固定 \(n\)。

solution

我们很容易构造 \(cnt=2n\) 的方案。甚至 \(cnt=n\) 好像也行,我不管。

不考虑这个循环位移。则我们如果固定了 \(cnt\),那么异或一的操作实际上是将区间 \([x_i,x_i+cnt-i]\) 异或一,对于第 \(i\) 次操作。

我们完全可以倒着做这个操作,让区间的长度递增,则第 \(i\) 次操作变成了:

  • 在 \(S\) 上选择一段长为 \(i\) 的区间异或一。
  • 目标:使得 \(S\) 清空,如果将 \(S\) 超过 \(n\) 的部分按顺序异或回来,叠起来。

我们再倒过来,我们设 \(F(S,cnt)\) 表示在第 \(cnt\) 步(未做 \(cnt\) 步时),\(S\) 是否有可能通过从 \(0\) 处得到,如果 \(F(S,cnt)\) 为真,则说明 \(T=0\) 时可以用 \(cnt\) 步解决原问题。

假如我们通过一波暗箱操作得到了 \(F\)(注意到 \(cnt\) 是 \(O(n)\) 的),对于询问,我们枚举 \(cnt\),然后因为原来的 \(T\) 跟着移动,我们让原来的 \(T\) 进行 \(cnt\) 次操作(但不修改),直接改掉 \(S\),然后询问另外的 \(S\)。

现在考虑如何求 \(F\),实际上我们可以直接暴力转移,枚举异或区间在哪里,然后异或上去就是了。

code

点击查看代码
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr,##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
typedef long long LL;
int read(int&len){
	static char a[40];
	scanf("%s",a+1);
	len=strlen(a+1);
	int res=0;
	for(int i=len;i>=1;i--) res=res<<1|(a[i]-'0');
	return res;
}
bool f[1<<20][45];
LL g[20];
LL getfull(int k){return (1ll<<k)-1;}
LL cover(LL S,int n){
	while(S>getfull(n)) S^=(S>>n)^(S>>n<<n);
	return S;
}
void printbin(int S,int n){
	#ifdef LOCAL
	for(int j=0;j<n;j++) debug("%d",(S>>j)&1);
	#endif
}
void dp(int n){
	memset(f,0,sizeof f);
	f[0][0]=1;
	for(int i=0;i<=n<<1;i++){
//		debug("g[%d]:",i);
		for(int j=0;j<n;j++) g[j]=cover(getfull(i+1)<<j,n);
//		debug("f[%d]:",i);
		for(int S=0;S<1<<n;S++){
			if(!f[S][i]) continue;
//			#ifdef LOCAL
//			printbin(S,n);
//			debug(",");
//			#endif
			for(int j=0;j<n;j++) f[S^g[j]][i+1]=1;//fwt exactly
		}
//		debug("\n");
	}
}
struct ask{
	int le,S,T,id;
	bool operator<(ask b){return le<b.le;}
} q[200010]; 
int n,m,bua[200010];
int main(){
	#ifdef LOCAL
	 	freopen("input.in","r",stdin);
	#endif
	scanf("%d%d",&m,&n);
	dp(n);
	for(int i=1;i<=m;i++) q[i].S=read(q[i].le),q[i].T=read(q[i].le),q[i].id=i;
//	sort(q+1,q+m+1);
	for(int i=1;i<=m;i++){
		int n=q[i].le,id=q[i].id,S=q[i].S,T=q[i].T;
//		if(q[i].le!=q[i-1].le) dp(n);//一开始以为询问的 n 都不同哈哈哈
		for(int&cnt=bua[id]=0;cnt<=n<<1;cnt++){
			if(f[S][cnt]) break;
			S^=cover(T<<cnt,n);
		}
	}
	for(int i=1;i<=m;i++) printf("%d\n",bua[i]);
	return 0;
}

标签:cnt,Off,int,题解,len,异或,USACO23JAN,操作,include
From: https://www.cnblogs.com/caijianhong/p/17073230.html

相关文章

  • 题解 【[USACO23JAN] Find and Replace G】
    problem有一个字符串\(S\),初始时为\(\tt'a'\),现在进行\(n\)次操作,第\(i\)次操作形如:将\(S\)中的所有的字符\(ch_i\)替换为字符串\(T_i\)。然后输出\(S[l......
  • 【题解】favorite school
    标准程序1:#include<bits/stdc++.h>usingnamespacestd;intt,del,cha,flag[4],check[4];strings;unordered_map<char,int>pos;intslove(intx,inty,intz,int......
  • Acwing 周赛88 题解
    比赛链接A题题目描述给定一个整数\(x\),请你找到严格大于\(x\)且各位数字均不相同的最小整数\(y\)。\(1000\lex\le9000\)做法分析发现数据范围很小,那么我们可以直......
  • 【题解】USACO 2023 January Sliver
    因为Glod打寄了,就来写写Sliver的题解吧,现在应该比赛结束了吧。A.FindAndReplace题目分析:我们可以对给定的串建出一种关系,也就是如果在上面的字符串中是字符\(c_1......
  • CF1098D 题解
    题意传送门对于一个元素个数大于\(1\)的可重集,每次取出两个数\(x,y\)合并。若\(x\ley\le2x\),则称其为危险合并。重复上述操作至无法合并。给你一个初始为空的可......
  • 【题解】[LNOI2022] 盒
    题目分析:我们可以对每一条边单独计算贡献,这样会发现贡献很好算:\[ans=\sum_{i=0}^{n-1}w_i\sum_{j=0}^S|j-s_i|\binom{i+j-1}{i-1}\binom{S-j+n-i-1}{n......
  • 【题解】P5169 xtq的异或和
    再强没有xtq!!!1思路多项式的正确用法。首先根据P4151[WC2011]最大XOR和路径的神秘结论,这里只需要任意求出原图的一棵生成树,以及所有只包含一条非树边的简单环就可以维......
  • 调用后台接口实现Excel导出功能以及导出乱码问题解决
    实现效果在导出表格数据的时候,通常分为两种情况页面列表数据导出接口返回数据导出这里主要介绍接口返回数据导出,关于页面的列表数据导出,请看另一篇:vue3+element表格......
  • CF1400E Clear the Multiset 题解 贪心+分治
    题目链接:http://codeforces.com/problemset/problem/1400/E题目大意:给定一个长度为\(n\)数列\(\{a_n\}\),你可以进行如下操作:操作1:任意选择一个区间\([l,r]\),使区间内......
  • P6327 区间加区间sin和 题解
    P6327区间加区间sin和题解第一道Ynoi(捂脸题目描述给出一个长度为\(n\)的整数序列\(a_1,a_2,\ldots,a_n\),进行\(m\)次操作,操作分为两类。操作\(1\):给出\(l,r,v......