【BZOJ4722】由乃

【BZOJ4722】由乃

题面

bzoj

题解

考虑到区间长度为\(14\)时子集个数\(2^{14}>14\times 1000\),由抽屉原理,区间长度最多为\(13\)(长度大于这个值就一定有解)。

那么对于一个区间我们可以暴力背包\(dp\)出来,然后\(bitset\)优化下就是\(\frac {13\times 1000}{64}\)的,如果转移时转移的状态与目前状态有交显然就有解。

对于区间立方用树状数组记一下每个数立方了多少次,立方后的数倍增预处理即可。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring> 
#include <cmath> 
#include <algorithm>
#include <bitset> 
using namespace std; 
inline int gi() {
    register int data = 0, w = 1;
    register char ch = 0;
    while (!isdigit(ch) && ch != '-') ch = getchar(); 
    if (ch == '-') w = -1, ch = getchar(); 
    while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar(); 
    return w * data; 
} 
const int MAX_N = 1e5 + 5; 
int N, Q, Mod, a[MAX_N], c[MAX_N]; 
inline int lb(int x) { return x & -x; } 
void Add(int x, int v) { while (x <= N) c[x] += v, x += lb(x); } 
int Sum(int x) { int res = 0; while (x) res += c[x], x -= lb(x); return res; } 
bitset<13001> f; 
int nxt[18][MAX_N]; 
int Trans(int x, int y) { 
	for (int i = 17; ~i; i--) 
		if (y >> i & 1) x = nxt[i][x]; 
	return x; 
} 
int main () { 
#ifndef ONLINE_JUDGE 
    freopen("cpp.in", "r", stdin); 
#endif 
	N = gi(), Q = gi(), Mod = gi(); 
	for (int i = 1; i <= N; i++) a[i] = gi(); 
	for (int i = 0; i < Mod; i++) nxt[0][i] = i * i * i % Mod; 
	for (int i = 1; i < 18; i++) 
		for (int j = 0; j < Mod; j++) nxt[i][j] = nxt[i - 1][nxt[i - 1][j]]; 
	while (Q--) { 
		int op = gi(), l = gi(), r = gi(); 
		if (op == 1) { 
			if (r - l + 1 >= 14) puts("Yuno"); 
			else { 
				f.reset(); 
				f[0] = 1; 
				for (int i = l; i <= r; i++) { 
					int val = Trans(a[i], Sum(i)) + 1; 
					if ((f & (f << val)).any()) { puts("Yuno"); goto Nxt; } 
					f |= f << val; 
				} 
				puts("Yuki"); 
			  Nxt : ; 
			} 
		} else Add(l, 1), Add(r + 1, -1); 
	} 
    return 0; 
} 
posted @ 2019-10-30 16:06  heyujun  阅读(211)  评论(1编辑  收藏  举报