BZOJ4722: 由乃
阿新 • • 發佈:2018-11-06
題意
給了你 個數,你需要支援以下兩種操作:
- 從 到 這段區間中選兩個不相交的下標集合 ,一個集合的權值為下標對應的數的和,問是否能挑選出兩個權值相等的集合;
- 將 到 這段區間中的數取立方;
對於每個 操作,如果能找到合法集合輸出Yuno,否則輸出Yuki;
題解
本題有個神奇的結論:當區間長度大於等於14時,必定能找到合法的兩個集合;怎麼理解這個結論呢,考慮將區間長度設為 ,那麼能夠選出的不同集合數為 ,考慮最壞情況,這些集合將能夠取的值全部取完了,那麼一共能取的值有 個( 是所有數能夠取到的最大值),本題的 ,列出不等式 ,如果集合數大於了能夠取的值的數量,那麼必然能夠找到兩個合法的集合,此時解出 ;接下來思路就很清晰了,對於每個詢問,如果詢問區間的長度大於等於14時直接輸出Yuno,要處理的就只有長度小於等於13的詢問了;因為長度很小,我們可以暴力列舉每個數選或者不選,但是這樣會有 的代價,無法接受,那麼我們運用 的思想,暴力去列舉長度一半的數的取值情況,但是考慮到兩個集合都在前半段或者都在後半段,所以還要多考慮一種選出來的數加起來為0的情況,所以每次的代價就降為了 ;現在考慮最後修改的問題,區間取立方,看似非常棘手,但是我們可以通過儲存他立方了幾次用的時候臨時去算的方式,把問題就變簡單了,所需要算的東西為 ,因為 很小,這個東西可以通過預處理倍增陣列算,比如現在我們要算一個 ,我們可以先算出 ,然後算 ,先預處理出 陣列,表示 , ;
#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;
}