题目请戳这里
题目大意:模拟一个简单的洗牌过程。C张牌,编号0~c-1,一次洗牌就是将从第p张牌开始的连续l张整体移到最前面。现在给s个操作,每个操作有r次重复洗牌动作,求洗完牌后的c张牌序列中,奇数位置的牌点数之和。
题目分析:由于只有一个操作,所以直接模拟一下就可以了。洗牌过程看起来很复杂,看穿了也就没什么了。一次操作相当于将前p张牌循环右移l的位置,重复r次,其实就是将前p张牌循环右移l*r次。直接模拟就可以了。
兴高采烈的撸了个splay,好慢的样子。。。早知道就直接用愉快的数组模拟了。
详情请见代码:
#include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 1000005; const int inf = 0x3f3f3f3f; int next[N]; struct node { int l,r,f,lazy,sizea,key; }tree[N]; int n,m,cnt,c,s; long long ans; void init() { tree[0].sizea = tree[0].lazy = tree[0].l = tree[0].r = tree[0].f = 0; tree[0].key = inf; for(int i = 0;i < N;i ++) next[i] = i + 1; } int newnode() { int p = next[0]; next[0] = next[p]; tree[p].lazy = 0; tree[p].f = tree[p].l = tree[p].r = 0; tree[p].sizea = 1; return p; } void delnode(int p) { next[p] = next[0]; next[0] = p; } void pushup(int rt) { if(rt) tree[rt].sizea = tree[tree[rt].l].sizea + tree[tree[rt].r].sizea + 1; } void pushdown(int rt) { if(!rt) return; int ls = tree[rt].l; int rs = tree[rt].r; if(tree[rt].lazy) { swap(tree[rt].l,tree[rt].r); if(ls) tree[ls].lazy ^= 1; if(rs) tree[rs].lazy ^= 1; tree[rt].lazy = 0; } } void zig(int x) { int p = tree[x].f; pushdown(p); pushdown(x); tree[p].l = tree[x].r; if(tree[x].r) tree[tree[x].r].f = p; pushup(p); tree[x].r = p; tree[x].f = tree[p].f; pushup(x); tree[p].f = x; if(tree[x].f == 0) return; if(tree[tree[x].f].l == tree[x].r) tree[tree[x].f].l = x; else tree[tree[x].f].r = x; } void zag(int x) { int p = tree[x].f; pushdown(p); pushdown(x); tree[p].r = tree[x].l; if(tree[x].l) tree[tree[x].l].f = p; pushup(p); tree[x].l = p; tree[x].f = tree[p].f; pushup(x); tree[p].f = x; if(tree[x].f == 0) return; if(tree[tree[x].f].l == tree[x].l) tree[tree[x].f].l = x; else tree[tree[x].f].r = x; } int splay(int x,int goal) { pushdown(x); while(tree[x].f != goal) { int p = tree[x].f; int g = tree[p].f; if(g == goal) { if(tree[p].l == x) zig(x); if(tree[p].r == x) zag(x); } else { if(tree[g].l == p && tree[p].l == x) zig(p),zig(x); else if(tree[g].l == p && tree[p].r == x) zag(x),zig(x); else if(tree[g].r == p && tree[p].r == x) zag(p),zag(x); else if(tree[g].r == p && tree[p].l == x) zig(x),zag(x); } } pushup(x); return x; } int build(int l,int r,int fa) { if(l > r) return 0; int mid = (l + r)>>1; int p = newnode(); tree[p].l = build(l,mid - 1,p); tree[p].key = cnt ++; tree[p].f = fa; tree[p].r = build(mid + 1,r,p); pushup(p); return p; } void prepare(int &root) { root = newnode(); tree[root].key = inf; tree[root].r = newnode(); tree[tree[root].r].key = inf; tree[tree[root].r].f = root; tree[tree[root].r].l = build(1,c,tree[root].r); pushup(tree[root].r); pushup(root); } int finda(int pos,int rt) { if(!rt) return 0; pushdown(rt); if(tree[tree[rt].l].sizea == pos - 1) return rt; if(tree[tree[rt].l].sizea >= pos) return finda(pos,tree[rt].l); else return finda(pos - tree[tree[rt].l].sizea - 1,tree[rt].r); } void Rotate_interval(int a,int b,int &root) { int l = finda(a,root); int r = finda(b + 2,root); root = splay(l,0); tree[root].r = splay(r,root); pushup(tree[root].r); pushup(root); } void Reverse(int a,int b,int &root) { Rotate_interval(a,b,root); tree[tree[tree[root].r].l].lazy ^= 1; } void dfs(int rt) { if(!rt) return; pushdown(rt); dfs(tree[rt].l); if(tree[rt].key != inf) cnt ++; if(cnt&1) ans += tree[rt].key; dfs(tree[rt].r); delnode(rt); } int main() { int t,i,cas,root; int pos,len,rep; cas = 0; init(); scanf("%d",&t); while(t --) { scanf("%d%d",&c,&s); ans = 0; cnt = 0; prepare(root); while(s --) { scanf("%d%d%d",&pos,&len,&rep); int length = len * rep; len += pos; length %= len; if(length == 0) continue; length = len - length; Reverse(1,length,root); Reverse(length + 1,len,root); Reverse(1,len,root);//debug(root } cnt = 0; dfs(root); printf("Case %d:\n",++cas); printf("%lld\n",ans); if(t) puts(""); } return 0; }
补上数组模拟的代码:
so easy!so fast!!!
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 1000005; int lcm[N],temp[N]; long long ans; int c,s,p,l,r; int main() { int t,i,j; int cas = 0; scanf("%d",&t); while(t --) { scanf("%d%d",&c,&s); for(i = 1;i <= c;i ++) lcm[i] = i - 1; while(s --) { scanf("%d%d%d",&p,&l,&r); int len = l * r; l += p; len %= l; if(len == 0) continue; if(len >= (l>>1)) { for(i = 1;i <= l - len;i ++) temp[i] = lcm[i]; for(;i <= l;i ++) lcm[i - l + len] = lcm[i]; for(i = len + 1;i <= l;i ++) lcm[i] = temp[i - len]; } else { for(i = l,j = 1;i >= l - len + 1;i --) temp[j ++] = lcm[i]; for(;i >= 1;i --) lcm[i + len] = lcm[i]; for(i = j - 1;i >= 1;i --) lcm[len - i + 1] = temp[i]; } } ans = 0; for(i = 1;i <= c;i += 2) ans += lcm[i]; printf("Case %d:\n",++cas); printf("%lld\n",ans); if(t) puts(""); } return 0; }