题意
给了你 n n n个数,你需要支持以下两种操作:
- 1 l r : 1\ l\ r: 1 l r: 从 l l l到 r r r这段区间中选两个不相交的下标集合 A , B A,B A,B,一个集合的权值为下标对应的数的和,问是否能挑选出两个权值相等的集合;
- 2 l r : 2\ l\ r: 2 l r: 将 l l l到 r r r这段区间中的数取立方;
对于每个 1 1 1操作,如果能找到合法集合输出Yuno,否则输出Yuki;
题解
本题有个神奇的结论:当区间长度大于等于14时,必定能找到合法的两个集合;怎么理解这个结论呢,考虑将区间长度设为 l e n len len,那么能够选出的不同集合数为 2 l e n 2^{len} 2len,考虑最坏情况,这些集合将能够取的值全部取完了,那么一共能取的值有 l e n ∗ v len*v len∗v个( v v v是所有数能够取到的最大值),本题的 v = 1000 v=1000 v=1000,列出不等式 2 l e n ≥ l e n ∗ v 2^{len}\geq len*v 2len≥len∗v,如果集合数大于了能够取的值的数量,那么必然能够找到两个合法的集合,此时解出 l e n = 14 len=14 len=14;接下来思路就很清晰了,对于每个询问,如果询问区间的长度大于等于14时直接输出Yuno,要处理的就只有长度小于等于13的询问了;因为长度很小,我们可以暴力枚举每个数选或者不选,但是这样会有 2 13 2^{13} 213的代价,无法接受,那么我们运用 m e e t i n t h e m i d d l e meet\ in\ the\ middle meet in the middle的思想,暴力去枚举长度一半的数的取值情况,但是考虑到两个集合都在前半段或者都在后半段,所以还要多考虑一种选出来的数加起来为0的情况,所以每次的代价就降为了 3 7 3^7 37;现在考虑最后修改的问题,区间取立方,看似非常棘手,但是我们可以通过保存他立方了几次用的时候临时去算的方式,把问题就变简单了,所需要算的东西为 A i 3 x A_i^{3^{x}} Ai3x,因为 v v v很小,这个东西可以通过预处理倍增数组算,比如现在我们要算一个 A i 3 6 A_i^{3^{6}} Ai36,我们可以先算出 g = A i 3 2 g=A_i^{3^{2}} g=Ai32,然后算 g 3 4 g^{3^{4}} g34,先预处理出 F [ i ] [ j ] F[i][j] F[i][j]数组,表示 i 3 j i^{3^{j}} i3j, F [ i ] [ j ] = F [ F [ i ] [ j − 1 ] ] [ j − 1 ] F[i][j]=F[F[i][j-1]][j-1] F[i][j]=F[F[i][j−1]][j−1];
#include<bits/stdc++.h>
#define Fst first
#define Snd second
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long LL;
typedef unsigned int UI;
typedef unsigned long long ULL;
template<typename T> inline void read(T& x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template<typename T, typename... U> inline void read(T& x, U& ... y) {
read(x), read(y...);
}
const int N=1e5+10,MAX=1e4,mlog=17;
int n,Q,P,H,Len;
int W[20],vis[N],A[N],F[1010][mlog];
bool Flag;
struct BinaryIndexedTree {
int X[N];
int Lowbit(int a) {
return a&-a;
}
void Modify(int l,int r) {
while(l<=n) {
++X[l];
l+=Lowbit(l);
}
++r;
while(r<=n) {
--X[r];
r+=Lowbit(r);
}
}
int Query(int pos) {
int res=0;
while(pos) {
res+=X[pos];
pos-=Lowbit(pos);
}
return res;
}
} BIT;
int Pow(int a,int k) {
int res=1;
for(int i=k;i;i>>=1) {
if(i&1) res=res*a%P;
a=a*a%P;
}
return res;
}
void DFS1(int cnt,int val,int g) {
if(cnt==H+1) {
if(!g) return;
if(!val) Flag=true;
if(val>0) vis[val]=Q;
return;
}
DFS1(cnt+1,val+W[cnt],g+1); if(Flag) return;
DFS1(cnt+1,val-W[cnt],g+1); if(Flag) return;
DFS1(cnt+1,val,g);
}
void DFS2(int cnt,int val,int g) {
if(cnt==Len+1) {
if(!g) return;
if(!val) Flag=true;
if(val>0&&vis[val]==Q) Flag=true;
return;
}
DFS2(cnt+1,val+W[cnt],g+1); if(Flag) return;
DFS2(cnt+1,val-W[cnt],g+1); if(Flag) return;
DFS2(cnt+1,val,g);
}
int Calc(int a,int k) {
for(int i=0;i<mlog;++i) if(k>>i&1) a=F[a][i];
return a;
}
int main() {
read(n,Q,P);
for(int i=0;i<P;++i) F[i][0]=i*i%P*i%P;
for(int j=1;j<mlog;++j) {
for(int i=0;i<P;++i)
F[i][j]=F[F[i][j-1]][j-1];
}
for(int i=1;i<=n;++i) read(A[i]);
while(Q--) {
int opt,l,r; read(opt,l,r);
if(opt==1) {
if(r-l+1>=14) {
puts("Yuno");
continue;
}
if(l==r) {
puts("Yuki");
continue;
}
Len=r-l+1; H=Len/2;
for(int i=l;i<=r;++i) W[i-l+1]=Calc(A[i],BIT.Query(i))+1;
Flag=false;
DFS1(1,0,0);
DFS2(H+1,0,0);
puts(Flag?"Yuno":"Yuki");
}
if(opt==2) BIT.Modify(l,r);
}
return 0;
}