2/3线性基与100%构造题

T140977 线性基 (hard version)

排序也没用啊

第一个数构造2^19+k

第二个数构造2^18+k

第三个数及以后构造2^18

会发现他们会向搞一个219+218之后完蛋

然后我们219+218+k显然最优解

如果这个k和1e6同阶就完蛋了....

然额这个会fst,第一个是n=2的时候,k!=0一定无解

第二个是k=0的时候随便构造一下就行了


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

int n, k;

int main() {
	scanf("%d%d", &n, &k);
	if(k != 0) {
		if(n == 2)puts("-1");
		else {
			printf("%d %d ", k + (1 << 19), k + (1 << 18));
			for(int i = 3; i <= n; ++i)printf("%d ", (1 << 18));
			puts("");
		}
	} else {
		for(int i = 1; i <= n; ++i)printf("%d ", (1 << 19));
		puts("");
	}
	return 0;
}


P4301 [CQOI2013] 新Nim游戏

k太小了吧?

先手必胜就是在最后异或起来不是0的时候,也就是说无论第二个人怎么拿走都无法出现0的局面

仔细想想我们线性基插入过程中插不进去的就能被异或成0....

而我们其实是想让这个值尽可能的小,也就是说大数能插进去,所以我们从大到小插入就行了

code:


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 1e5 + 7;
int n, a[MAXN], b[MAXN];
long long ans;

int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i)scanf("%d", a + i);
	sort(a + 1, a + n + 1);
	for(int i = n; i >= 1; --i) {
		int tmp = a[i];
		// printf("%d?\n", tmp);
		bool flg = 1;
		for(int k = 30; k >= 0; --k) {
			if(tmp & (1 << k)) {
				if(b[k])
					tmp ^= b[k];
				else {
					b[k] = tmp;
					flg = 0;
					break;
				}
			}
		}
		// printf("%d?%d\namespace", flg, tmp);
		if(flg)ans += a[i];
	}
	printf("%lld\n", ans);
	return 0;
}


P3226 [HNOI2012]集合选数

显然这个东西每个数能选的是一样的qwq

然后.....QAQ了

容斥一下吗?完蛋了,和枚举自己没啥区别

点开标签: 状压?

啊这...

等等啊,这个东西从小到大DP?

啊这.....

打开题解:显然这个结论很难搞,我们要找一个等价命题

构造一个矩阵,第一行第一列的值为1,每一行后面的数都是前面那个数的两倍

每列的数是他上面的数的三倍


1  2  4  8   16  32  ...
3  6  12 24  48  96  ...
9  18 36 72  ...
27 ...

每个数都是前面那个数2倍,最后长为log2nlog_2n宽为log3nlog_3n

然后就发现每个数我们选了他就不能选择相邻的,否则会自闭

然后这样显然没有包括所有的数,可以枚举并check所有的数qwq

code:


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int P = 1e9 + 1;
const int MAXN = 1e5 + 7;
const int MAXS = 4096;
const int MAXH = 20;
int n, p;
int vis[MAXN], flg[MAXN], Vvis[MAXN], num[MAXN];
int dp[MAXH][MAXS];
ll ans;
inline void build(int x) {
	p = 1;
	for(int i = x; i <= n; i = i * 2, ++p) {
		num[p] = 0;
		flg[p] = 0;
		for(int j = i, q = 1; j <= n; j = j * 3, ++q) {
			++num[p];
			Vvis[j] = 1;//值已经有了qwq
			flg[p] |= (1 << (q - 1));
		}
	}
	p--;
	for(int S = flg[1], qwq = 1; S >= 0 && qwq; S = (S - 1)&flg[1]) {
		if(S == 0)
			qwq = 0;
		if(vis[S]) {
			dp[1][S] = 1;
		}
	}
	return ;
}

void solve(int x) {
	memset(dp, 0, sizeof(dp));
	build(x);
	for(int i = 2; i <= p; ++i) {
		for(int S1 = flg[i], qwq = 1; S1 >= 0 && qwq; S1 = (S1 - 1)&flg[i]) {
			if(S1 == 0)qwq = 0;
			if(!vis[S1])continue;
			for(int S2 = flg[i - 1], qaq = 1; S2 >= 0 && qaq; S2 = (S2 - 1)&flg[i - 1]) {
				if(S2 == 0)qaq = 0;
				if(!vis[S2])continue;
				if(!(S2 & S1)) {
					dp[i][S1] = (dp[i][S1] + dp[i - 1][S2]) % P;
				}
			}
		}
	}
	ll Sum = 0;
	for(int S = flg[p], qwq = 1; S >= 0 && qwq; S = (S - 1)&flg[p]) {
		if(S == 0)qwq = 0;
		if(!vis[S])continue;
		Sum = (Sum + dp[p][S]) % P;
	}
	ans = 1ll * ans * Sum % P;
}

int main() {
	scanf("%d", &n);
	for(int i = 0; i <= 4096; ++i)
		vis[i] = (((i << 1) & i) || ((i >> 1) & i)) ? 0 : 1;
	ans = 1;
	for(int i = 1; i <= n; ++i)
		if(!Vvis[i]) {
			solve(i);
		}
	printf("%lld\n", ans);
	return 0;
}