题目链接:http://codeforces.com/contest/817

A. Treasure Hunt

题意:给定一个起点一个终点坐标,然后用题目中给的四种方法走任意次(X,Y的值在下一行输入)能从起点走到终点就输出YES,反之NO。解法:容易发现,(a,b)变换成了(a+k1x, b+k2y),那么k1和k2的奇偶性一定是相同的,还有一种特殊情况就是k1,k2不是整数,这个可以特判一下就行。

#include <bits/stdc++.h>
using namespace std;
int x1,y1,x2,y2,x,y;

int main(){
    scanf("%d%d%d%d%d%d",&x1,&y1,&x2,&y2,&x,&y);
    if(abs(x1-x2)%x==0&&abs(y1-y2)%y==0&&(abs(x1-x2)/x)%2==(abs(y1-y2)/y)%2){
        puts("YES");
    }
    else{
        puts("NO");
    }
    return 0;
}

B. Makes And The Product

题意:求三元组(i,j,k)的个数,其中满足a[i]*a[j]*a[k]要最小。
解法:简单排列组合,排序之后算出最小的3个数是什么,然后统计下这3个数的出现次数,然后简单排列组合算就可以了。

#include <bits/stdc++.h>
using namespace std;
long long ans,n,a[100010],cnt1,cnt2,cnt3;

int main(){
    scanf("%d",&n);
    for(int i=1; i<=n; i++) scanf("%lld",&a[i]);
    sort(a+1,a+n+1);
    long long mx1=a[1], mx2 = a[2], mx3 = a[3];
    for(int i=1; i<=n; i++){
        if(a[i]==mx1) cnt1++;
        if(a[i]==mx2) cnt2++;
        if(a[i]==mx3) cnt3++;
    }
    ans = 1;
    long long t = cnt1;
    if(mx2 != mx1){
        t += cnt2;
    }
    if(mx3 != mx2){
        t += cnt3;
    }
    if(t <= 3){
        puts("1");
        return 0;
    }
    if(mx1==mx2&&mx2==mx3){
        ans = cnt1*(cnt1-1)*(cnt1-2)/6;
    }
    else if(mx2==mx3){
        ans=cnt1*(cnt2*(cnt2-1)/2);
    }
    else if(mx1==mx2){
        ans=cnt3*(cnt1*(cnt1-1)/2);
    }
    else{
        ans=cnt1*cnt2*cnt3;
    }
    printf("%lld\n", ans);
}

C. Really Big Numbers
题意:找一个数n,ans为n的各个位之和,n-ans>=s才能称为大数
解法:水题,二分去check就可以了。

#include <bits/stdc++.h>
using namespace std;
long long n, s;
long long f(long long x){
    long long sum=0;
    while(x){
        sum+=x%10;
        x/=10;
    }
    return sum;
}
bool check(long long mid){
    long long x = n-mid+1;
    long long t = f(x);
    if(x-t>=s){
        return true;
    }
    else{
        return false;
    }
}
int main(){
    while(~scanf("%lld%lld",&n,&s)){
        long long l=0, r=n, ans = 0;
        while(l<=r){
            long long mid = (l+r)/2;
            if(check(mid)) ans=mid,l=mid+1;
            else r=mid-1;
        }
        printf("%lld\n", ans);
    }
    return 0;
}

D. Imbalanced Array
题意:给你n个数a[1..n]定义连续子段imbalance值为最大值和最小值的差,要你求这个数组的imbalance总值
解法:考虑每个位置作为最值向两边的最大拓展,最小值取负号,最大值取正号,求和即可。怎么去找呢?可以维护一个单调递增栈、单调递减栈。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000010;
int n, a[maxn], lmax[maxn], rmax[maxn], lmin[maxn], rmin[maxn];
int stk[maxn];
int main()
{
    while(~scanf("%d", &n)){
        for(int i=1; i<=n; i++) scanf("%d", &a[i]);
        int top=0;
        for(int i=1; i<=n; i++){
            while(top>0&&a[stk[top-1]]<=a[i]) top--;
            if(top==0) lmax[i]=1;
            else lmax[i]=stk[top-1]+1;
            stk[top++] = i;
        }
        top = 0;
        for(int i=n; i>=1; i--){
            while(top>0&&a[stk[top-1]]<a[i]) top--;
            if(top==0) rmax[i]=n;
            else rmax[i]=stk[top-1]-1;
            stk[top++]=i;
        }
        top = 0;
        for(int i=1; i<=n; i++){
            while(top>0&&a[stk[top-1]]>=a[i]) top--;
            if(top==0) lmin[i]=1;
            else lmin[i]=stk[top-1]+1;
            stk[top++]=i;
        }
        top = 0;
        for(int i=n; i>=1; i--){
            while(top>0&&a[stk[top-1]]>a[i]) top--;
            if(top==0) rmin[i]=n;
            else rmin[i]=stk[top-1]-1;
            stk[top++]=i;
        }
        long long ans = 0;
        for(int i=1; i<=n; i++){
            ans -= 1LL*a[i]*(rmin[i]-i+1)*(i-lmin[i]+1);
            ans += 1LL*a[i]*(rmax[i]-i+1)*(i-lmax[i]+1);
        }
        printf("%lld\n", ans);
    }
    return 0;
}

E. Choosing The Commander

题意:1增加一个数,2删除一个数,3求所有数^k

#include <bits/stdc++.h>
using namespace std;
const int maxn = 4e6+7;
struct node{
    int ch[maxn][2], val[maxn], root, L;
    int newnode(){
        ch[L][0]=ch[L][1]=-1;
        return L++;
    }
    void init(){
        L=0,root=newnode();
    }
    void insert(int x){
        int now=root;
        for(int j=30; j>=0; j--){
            int go = (x&(1<<j))?1:0;
            if(ch[now][go]==-1){
                ch[now][go]=newnode();
                now = ch[now][go];
            }
            else{
                now=ch[now][go];
            }
            val[now]++;
        }
    }
    void del(int x){
        int now=root;
        for(int j=30; j>=0; j--){
            int go = (x&(1<<j))?1:0;
            if(ch[now][go]==-1){
                ch[now][go]=newnode();
                now = ch[now][go];
            }
            else{
                now=ch[now][go];
            }
            val[now]--;
        }
    }
    int query(int x, int y){
        int num1[32]={0}, num2[32]={0}, cnt1 = 0, cnt2 = 0;
        while(x){
            num1[cnt1++]=x%2;
            x/=2;
        }
        while(y){
            num2[cnt2++]=y%2;
            y/=2;
        }
        int ans = 0;
        int now=root;
        for(int j=30; j>=0; j--){
            if(num2[j]==0){
                if(ch[now][num1[j]]==-1) break;
                now = ch[now][num1[j]];
            }
            else{
                if(ch[now][num1[j]]) ans+=val[ch[now][num1[j]]];
                if(ch[now][!num1[j]]==-1) break;
                now = ch[now][!num1[j]];
            }
        }
        return ans;
    }
}trie;

int main(){
    int q;
    scanf("%d", &q);
    trie.init();
    for(int i=1; i<=q; i++){
        int op, x, y;
        scanf("%d %d", &op, &x);
        if(op == 1) trie.insert(x);
        else if(op == 2) trie.del(x);
        else{
            scanf("%d", &y);
            printf("%d\n", trie.query(x,y));
        }
    }
    return 0;
}

F. MEX Queries
题意:如题:http://codeforces.com/contest/817/problem/F
解法:这道题首先要离散化,这道题唯一需要注意的也就是离散化,我们考虑一下答案可能是什么,只可能是1,l, r+1。所以我们把这3个点丢进去离散化就可以了。接下来就remove操作就是将l-r区间赋值为0, add操作就是将l-r区间赋值为1,而invert操作就是区间取xor,通过重新计算区间和值进行实现。然后每次询问就是查询最左边的0的位置,可以通过维护区间和值进行查询.。时间复杂度O(qlog(q)

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
typedef long long LL;
int n;
struct Q{
    int op;
    LL l,r;
}q[maxn];
struct node{
    int l,r,len,tag,rev,sum;
}tree[maxn*50];
int cnt = 0;
unordered_map <LL, int> mp;
LL x[10*maxn];
void build(int l, int r, int rt)
{
    tree[rt].l=l,tree[rt].r=r,tree[rt].tag=-1,tree[rt].sum=0,tree[rt].rev=0, tree[rt].len = r-l+1;
    if(l==r) return;
    int mid = (l+r)/2;
    build(l,mid,rt*2);
    build(mid+1,r,rt*2+1);
}
void pushup(int rt){
    tree[rt].sum = tree[rt*2].sum + tree[rt*2+1].sum;
}
void pushdown(int rt){
    if(tree[rt].tag!=-1){
        tree[rt*2].tag=tree[rt].tag;
        tree[rt*2+1].tag=tree[rt].tag;
        tree[rt*2].sum=tree[rt*2].len*tree[rt].tag;
        tree[rt*2+1].sum=tree[rt*2+1].len*tree[rt].tag;
        tree[rt*2].rev=tree[rt*2+1].rev=0;
        tree[rt].tag = -1;
    }
    if(tree[rt].rev){
        tree[rt*2].rev^=tree[rt].rev;
        tree[rt*2+1].rev^=tree[rt].rev;
        tree[rt*2].sum=tree[rt*2].len-tree[rt*2].sum;
        tree[rt*2+1].sum=tree[rt*2+1].len-tree[rt*2+1].sum;
        tree[rt].rev = 0;
    }
}
void update1(int L, int R, int val, int rt){//区间改成val
    if(L<=tree[rt].l&&tree[rt].r<=R){
        tree[rt].sum = val*(R-L+1);
        tree[rt].tag = val;
        tree[rt].rev = 0;
        return;
    }
    pushdown(rt);
    int mid = (tree[rt].l + tree[rt].r)/2;
    if(R<=mid) update1(L,R,val,rt*2);
    else if(L>mid) update1(L,R,val,rt*2+1);
    else{
        update1(L,mid,val,rt*2);
        update1(mid+1,R,val,rt*2+1);
    }
    pushup(rt);
}
void update2(int L, int R, int rt){//区间翻转
    if(L <= tree[rt].l && tree[rt].r <= R){
        tree[rt].sum = (R-L+1) - tree[rt].sum;
        tree[rt].rev ^= 1;
        return ;
    }
    pushdown(rt);
    int mid = (tree[rt].l+tree[rt].r)/2;
    if(R<=mid) update2(L,R,rt*2);
    else if(L>mid) update2(L,R,rt*2+1);
    else{
        update2(L,mid,rt*2);
        update2(mid+1,R,rt*2+1);
    }
    pushup(rt);
}
int query(int rt)
{
    if(tree[rt].l == tree[rt].r) return tree[rt].l;
    pushdown(rt);
    if(tree[rt*2].sum == tree[rt*2].len){
        return query(rt*2+1);
    }
    else{
        return query(rt*2);
    }
}
int main()
{
    int T;
    while(~scanf("%d", &n)){
        mp.clear();
        cnt = 0;
        for(int i=1; i<=n; i++){
            scanf("%d %lld %lld", &q[i].op,&q[i].l,&q[i].r);
            x[++cnt] = q[i].l;
            x[++cnt] = q[i].l+1;
            x[++cnt] = q[i].r;
            x[++cnt] = q[i].r+1;
        }
        x[++cnt] = 1;
        x[++cnt] = 1e18+5;
        sort(x+1, x+cnt+1);
        cnt = unique(x+1, x+cnt+1)-x-1;
        for(int i=1; i<=cnt; i++){
            mp[x[i]]= i;
        }
        build(1, cnt, 1);
        for(int i=1; i<=n; i++){
            int l = mp[q[i].l];
            int r = mp[q[i].r+1]-1;
            if(q[i].op == 1){
                update1(l, r, 1, 1);
            }
            else if(q[i].op == 2){
                update1(l, r, 0, 1);
            }
            else{
                update2(l,r,1);
            }
            printf("%lld\n", x[query(1)]);
        }
    }
    return 0;
}