传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4722
首先序列长度大于20一定是Yes
因为考虑长为n的区间,选择方案数有$2^n$种,但权值只有$1000n$种,由于两集合不能相交大体上估计一下是20
经过实践证明数据只需要>=10就是Yes了
于是乎用一个标记永久化的线段树维护单点的值(upd:呃……似乎树状数组就好了……)
小范围$3^n$暴力即可
($3^9=19683$……居然过了……)
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+5; int a[maxn],b[233],siz; int n,m,v,phi[2333]; int ansx,ansy; bool dfs(int x){ if(x==siz+1){ if(ansx&&ansx==ansy){ return true; } return false; } if(dfs(x+1)) return true; ansx+=b[x]+1; if(dfs(x+1)) return true; ansx-=b[x]+1; ansy+=b[x]+1; if(dfs(x+1)) return true; ansy-=b[x]+1; return false; } #define id(l,r) ((l+r)|(l!=r)) int s[maxn*2]; void add(int l,int r,int l0,int r0){ if(l0<=l&&r0>=r){ s[id(l,r)]++; return ; } int mid=(l+r)>>1; if(l0<=mid)add(l,mid,l0,r0); if(r0>mid)add(mid+1,r,l0,r0); } int Q(int l,int r,int ps){ if(l==r)return s[id(l,r)]; int mid=(l+r)>>1,ans=s[id(l,r)]; if(ps<=mid)ans+=Q(l,mid,ps); else ans+=Q(mid+1,r,ps); return ans; } int pw(int x,int k,int p){ int ans=1%p; for(;k;k>>=1){ if(k&1)ans=ans*x%p; x=x*x%p; }return ans; } int pw(int x,int k){ int ans=1; for(;k;k>>=1){ if(k&1)ans=ans*x; x=x*x; }return ans; } int get(int ps){ int x=a; int t=Q(1,n,ps); if(t<=15)return pw(x,pw(3,t),v); return pw(x,pw(3,t,phi[v])+phi[v],v); } int main(){ // freopen("bzoj4722.in","r",stdin); scanf("%d%d%d",&n,&m,&v); for(int i=v;i<=v;i++) for(int j=1;j<=i;j++) if(__gcd(i,j)==1) phi[i]++; for(int i=1;i<=n;i++) scanf("%d",&a[i]); while(m--){ int op,l,r; scanf("%d%d%d",&op,&l,&r); if(op==1){ if(r-l+1>=10)puts("Yuno"); else{ ansx=ansy=siz=0; for(int i=l;i<=r;i++){ b[++siz]=get(i); //cerr<<b[siz]<<" \n"[i==r]; } puts(dfs(1)?"Yuno":"Yuki"); } }else{ add(1,n,l,r); } } return 0; }