Codeforces 817

 

 

A

你可以按如下方式移动

问能不能从给定的一个坐标走到另一个。

【solution】

裸,奇偶性注意

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
#include<map>
#include<vector>
#include<set>
#define il inline
#define re register
using namespace std;
int a1,b1,a2,b2,x,y,a,b;
int main(){
    cin>>a1>>b1>>a2>>b2>>x>>y;
    if((a1-a2)%x==0&&(b1-b2)%y==0){
        a=(a1-a2)/x;
        b=(b1-b2)/y;
        if((a-b)%2==0){
            cout<<"YES\n";
        }
        else cout<<"NO\n";
    }
    else cout<<"NO\n";
    return 0;
}

 

 

 

B

After returning from the army Makes received a gift — an array a consisting of n positive integer numbers. He hadn't been solving problems for a long time, so he became interested to answer a particular question: how many triples of indices (i,  j,  k) (i < j < k), such that ai·aj·ak is minimum possible, are there in the array? Help him with it!

Input

The first line of input contains a positive integer number n (3 ≤ n ≤ 105) — the number of elements in array a. The second line contains n positive integer numbers ai (1 ≤ ai ≤ 109) — the elements of a given array.

Output

Print one number — the quantity of triples (i,  j,  k) such that i,  j and k are pairwise distinct and ai·aj·ak is minimum possible.

【solution】

就是问成绩最小的有序三元组有多少个,排序搞定 

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
#include<map>
#include<vector>
#include<set>
#define il inline
#define re register
using namespace std;
typedef long long ll;
const int N=1000001;
int n,a[N],b[N],c[N],m;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);b[i]=a[i];
    }
    sort(b+1,b+n+1);
    m=unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;i++)
        a[i]=lower_bound(b+1,b+m+1,a[i])-b;
    for(int i=1;i<=n;i++) c[a[i]]++;
    if(c[1]>=3){
        cout<<((ll)c[1]*(c[1]-1)*(c[1]-2)/6)<<endl;
    }
    else{
        if(c[1]==2){
            cout<<c[2]<<endl;
        }
        else if(c[1]==1){
            if(c[2]>=2) cout<<((ll)c[2]*(c[2]-1)/2)<<endl;
            else cout<<c[3]<<endl;
        }
    }
    return 0;
}

 

 

 

C

f(i)表示i所有数位的和

问满足 i-f(i)>=s  (i<=n) 的有多少个

n,s<=10^18

【solution】

显而易见,f(i)最大也就是18*9=162,所以[s,s+1000]这个范围直接枚举,更大的肯定是满足的。

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
#include<map>
#include<vector>
#include<set>
#define il inline
#define re register
using namespace std;
typedef long long ll;
ll n,m,ans;
il ll f(ll n){
    ll res=0;
    for(;n;n/=10)
        res+=(n%10);
    return res;
}
int main(){
    cin>>n>>m;
    for(ll i=m;i<=n&&i<=m+10000;i++){
        if(i-f(i)>=m) ans++;
    }
    ans+=n-min(n,m+10000);
    cout<<ans;
    return 0;
}

 

 

 

D

给定一个长度为n的数组a (n<=100000)

求sigma(max(i,j)-min(i,j)) (1<=i<=j<=n)

【solution】

显然的把最大和最小拆开做

我们采用分治算法解决问题

我们去除一段中最大(小)统计贡献,然后左右递归

最多递归n次,采用st算法加速

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
#include<map>
#include<vector>
#include<set>
#define il inline
#define re register
#define cmin(x,y) (a[x]<a[y]?x:y)
#define cmax(x,y) (a[x]>a[y]?x:y) 
using namespace std;
typedef long long ll;
const int N=1111111;
int n,s[N][21],t[N][21],a[N],k[N];
ll ans=0;
il int getmin(int l,int r){
    int h=r-l+1,p=r-(1<<k[h])+1;
    return cmin(s[l][k[h]],s[p][k[h]]);
}
il int getmax(int l,int r){
    int h=r-l+1,p=r-(1<<k[h])+1;
    return cmax(t[l][k[h]],t[p][k[h]]);
}
il void dfs1(int l,int r){
    if(l>r) return;
    int mid=getmin(l,r);
    ans-=(ll)a[mid]*(mid-l+1)*(r-mid+1);
    dfs1(l,mid-1);dfs1(mid+1,r);
}
il void dfs2(int l,int r){
    if(l>r) return;
    int mid=getmax(l,r);
    ans+=(ll)a[mid]*(mid-l+1)*(r-mid+1);
    dfs2(l,mid-1);dfs2(mid+1,r);
}
int main(){
    scanf("%d",&n);
    for(int i=1,K=0;i<=n;i++){
        if((1<<K+1)<i) K++;
        scanf("%d",&a[i]);k[i]=K;
        t[i][0]=s[i][0]=i;
    }
    for(int j=1;j<=k[n];j++){
        for(int i=1,k=(1<<j-1)+1;k<=n;i++,k++){
            s[i][j]=cmin(s[i][j-1],s[k][j-1]);
            t[i][j]=cmax(t[i][j-1],t[k][j-1]);
        }
    }
    dfs1(1,n);dfs2(1,n);
    cout<<ans;
    return 0;
}

 

 

 

E

维护一个正整数构成的集合p

支持三个操作

1、添加一个元素

2、删除一个已经存在的元素

3、输入x,y,询问集合中满足pi^x<y的元素有多少个。

【solution】

解法十分的巧妙,把元素转化成二进制,建立trie树,问题迎刃而解。

希望这种做法能在难题里得到应用。

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
#include<map>
#include<vector>
#include<set>
#define il inline
#define re register
using namespace std;
const int N=1000001;
int n=1,Q,c[N*10][2],s[N*10];
int main(){
    scanf("%d",&Q);
    for(int ii=1,jj,x,y,h,ans;ii<=Q;ii++){
        scanf("%d%d",&jj,&x);h=1;
        if(jj==1){
            for(int i=30,j;i>=0;i--){
                j=(x&(1<<i))>0;
                if(!c[h][j]) c[h][j]=(++n);
                h=c[h][j];s[h]++;
            }
        }
        if(jj==2){
            for(int i=30,j;i>=0;i--){
                j=(x&(1<<i))>0;
                h=c[h][j];s[h]--;
            }
        }
        if(jj==3){
            scanf("%d",&y);ans=0;
            for(int i=30;i>=0;i--){
                if(y&(1<<i)){
                    if(x&(1<<i)){
                        ans+=s[c[h][1]];
                        h=c[h][0];
                    }
                    else{
                        ans+=s[c[h][0]];
                        h=c[h][1];
                    }
                }
                else{
                    if(x&(1<<i)) h=c[h][1];
                    else h=c[h][0];
                }
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}

 

 

 

F

维护区间裸题

1、染黑一个区间

2、染白一个区间

3、翻转一个区间

操作后要求输出最靠左的黑点的坐标

【solution】

线段树

细节:有的标记不能简单覆盖!【以前一直忽略的!】

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
#include<map>
#include<vector>
#include<set>
#define il inline
#define re register
using namespace std;
typedef long long ll;
const int N=2000001;
int t[N],Q,m=1,L[N],R[N],s[N],p,c[N];
ll l[N],r[N],b[N];
il int d(int a,int b){
    if(a==0) return b;
    if(b<3) return b;
    return 3-a;
}
il void pushdown(int i){
    if(t[i]==0) return;
    if(t[i]==1){
        t[i+i]=t[i+i+1]=1;
        s[i+i]=R[i+i]-L[i+i]+1;
        s[i+i+1]=R[i+i+1]-L[i+i+1]+1;
        t[i]=0;
    }
    else if(t[i]==2){
        t[i+i]=t[i+i+1]=2;
        s[i+i]=s[i+i+1]=0;
        t[i]=0;
    }
    else if(t[i]==3){
        t[i+i]=d(t[i+i],t[i]);
        t[i+i+1]=d(t[i+i+1],t[i]);
        s[i+i]=R[i+i]-L[i+i]+1-s[i+i];
        s[i+i+1]=R[i+i+1]-L[i+i+1]+1-s[i+i+1];
        t[i]=0;
    }
}
il void work(int i,int p,int q,int v){
    if(q<L[i]||p>R[i]) return;
    if(i<m) pushdown(i);
    if(p<=L[i]&&R[i]<=q){
        if(v==1) s[i]=R[i]-L[i]+1;
        if(v==2) s[i]=0;
        if(v==3) s[i]=R[i]-L[i]+1-s[i];
        t[i]=d(t[i],v);
        return;
    }
    work(i+i,p,q,v);work(i+i+1,p,q,v);
    s[i]=s[i+i]+s[i+i+1];
}
il int query(int i){
    if(i<m) pushdown(i);
    if(s[i]==0) return L[i];
    if(s[i+i]<R[i+i]-L[i+i]+1) return query(i+i);
    else return query(i+i+1);
}
int main(){
    scanf("%d",&Q);
    for(int i=1;i<=Q;i++){
        scanf("%d%I64d%I64d",&c[i],&l[i],&r[i]);
        b[++p]=l[i];b[++p]=l[i]+1;
        b[++p]=r[i];b[++p]=r[i]+1;
    }
    b[++p]=1;    
    sort(b+1,b+p+1);
    p=unique(b+1,b+p+1)-b-1;
    for(int i=1;i<=Q;i++){
        l[i]=lower_bound(b+1,b+p+1,l[i])-b;
        r[i]=lower_bound(b+1,b+p+1,r[i])-b;
    }
    while(m<p) m<<=1;
    for(int i=m;i<m+m;i++)
        L[i]=R[i]=i-m+1;
    for(int i=m-1;i;i--)
        L[i]=L[i+i],R[i]=R[i+i+1];
    for(int i=1;i<=Q;i++){
        work(1,l[i],r[i],c[i]);
        printf("%I64d\n",b[query(1)]);
    }
    return 0;
}

 

posted @ 2017-06-17 00:49  ExiledPoet  阅读(437)  评论(0编辑  收藏  举报