[bzoj4722] 由乃
题意:两种操作。1、将所给区间划分成两个集合,集合中的元素的贡献为a[i]+1,求是否能找出两个集合使两个集合的总贡献相等。2、区间立方(有模数)
题解:
倍增+线段树+搜索(meet in the middle)
区间立方:由于模数比较小,我们可以用倍增预处理某个数的2^j次立方,然后用线段树维护查询的次数,单次复杂度:O(logn)
划分集合:
首先有个结论,由于所有数的最大范围只有1000,所以超过13个数一定能通过加减等于0
对于范围小于等于13的区间,首先查出每个数操作后得到的数,然后用meet in the middle暴搜出解,单次复杂度:O(logn+3^7)
总复杂大概是:O(m*(logn+3^7))
然后这题我犯了一大堆傻逼错误,调了一个下午,我也是醉了
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 #define ll long long 8 #define ls x<<1 9 #define rs x<<1|1 10 #define N 100010 11 #define M 15000 12 using namespace std; 13 14 int n,m,v,top; 15 int a[N],tr[N*4],lazy[N*4],f[1010][22],st[N],val[20]; 16 bool flg,vis[N]; 17 18 int gi() { 19 int x=0,o=1; char ch=getchar(); 20 while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar(); 21 if(ch=='-') o=-1,ch=getchar(); 22 while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); 23 return o*x; 24 } 25 26 void pre() { 27 for(int i=0; i<v; i++) f[i][0]=i*i*i%v;//错点1:初始化对象错误 28 for(int j=1; j<=20; j++) 29 for(int i=0; i<v; i++) 30 f[i][j]=f[f[i][j-1]][j-1]; 31 } 32 33 void pushdown(int x) { 34 if(!lazy[x]) return; 35 tr[ls]+=lazy[x],tr[rs]+=lazy[x]; 36 lazy[ls]+=lazy[x],lazy[rs]+=lazy[x]; 37 lazy[x]=0; 38 } 39 40 void update(int x, int l, int r, int ql, int qr) { 41 if(ql<=l && r<=qr) { 42 tr[x]++,lazy[x]++;//其实只要开一个就够了,反正每次只会查询叶子= =、 43 return; 44 } 45 pushdown(x); 46 int mid=(l+r)>>1; 47 if(qr<=mid) update(ls,l,mid,ql,qr); 48 else if(ql>mid) update(rs,mid+1,r,ql,qr); 49 else update(ls,l,mid,ql,mid),update(rs,mid+1,r,mid+1,qr); 50 } 51 52 int query(int x, int l, int r, int qx) { 53 if(l==r) return tr[x]; 54 pushdown(x);//错点3:查询时没有pushdown 55 int mid=(l+r)>>1; 56 if(qx<=mid) return query(ls,l,mid,qx); 57 else return query(rs,mid+1,r,qx); 58 } 59 60 int get(int x) { 61 int y=query(1,1,n,x),ret=a[x]; 62 for(int i=20; i>=0; i--) { 63 if(y&(1<<i)) ret=f[ret][i]; 64 } 65 return ret; 66 } 67 68 void dfs1(int dep, int k, int sum, int siz) { 69 if(dep>k) { 70 vis[sum+M]=1,st[++top]=sum; 71 if(!sum && siz) flg=1; 72 return; 73 } 74 dfs1(dep+1,k,sum,siz); 75 if(flg) return; 76 dfs1(dep+1,k,sum+val[dep]+1,siz+1); 77 if(flg) return; 78 dfs1(dep+1,k,sum-val[dep]-1,siz+1); 79 } 80 81 void dfs2(int dep, int k, int sum, int siz) { 82 if(dep>k) { 83 if((vis[-sum+M] && sum!=0) || (!sum && siz)) flg=1; 84 return; 85 } 86 dfs2(dep+1,k,sum,siz); 87 if(flg) return;//错点5:没打分号 88 dfs2(dep+1,k,sum+val[dep]+1,siz+1); 89 if(flg) return; 90 dfs2(dep+1,k,sum-val[dep]-1,siz+1); 91 } 92 93 bool check(int x) { 94 for(int i=1; i<=top; i++) vis[st[i]+M]=0; 95 top=0,flg=0; 96 dfs1(1,x/2,0,0); 97 if(flg) return true; 98 dfs2(x/2+1,x,0,0); 99 if(flg) return true; 100 return false;//错点4:返回false时没有清空数组 101 } 102 103 int main() { 104 n=gi(),m=gi(),v=gi(); 105 for(int i=1; i<=n; i++) a[i]=gi(); 106 pre(); 107 for(int i=1; i<=m; i++) { 108 int op=gi(),l=gi(),r=gi(); 109 if(op==2) update(1,1,n,l,r); 110 else { 111 if(r-l+1>13) puts("Yuno"); 112 else { 113 for(int j=l; j<=r; j++) val[j-l+1]=get(j);//错点2:重复用i循环 114 if(check(r-l+1)) puts("Yuno"); 115 else puts("Yuki"); 116 } 117 } 118 } 119 return 0; 120 }