zoukankan      html  css  js  c++  java
  • 2018年全国多校算法寒假训练营练习比赛(第五场)

    逆序数

    题解:用树状数组进行计算有多少个前面比他大的数,只需要getsum(MAX)-getsum(a[i]),getsum(MAX)得到的是当前a[i]及出现在之前所有的数的个数,getsum(a[i])得到的是比a[i]在a[i]之前小于等于它的数的个数,相减就是比它大的个数;

     1 #include<algorithm>
     2 #include<cstdio>
     3 #define ll long long
     4 using namespace std;
     5 const int N =1e5+5;
     6 int a[N];
     7 int c[N];
     8 void update(int x){
     9     while(x<=N){
    10         c[x]++;
    11         x+=x&-x;
    12     }
    13 }
    14 int getsum(int x){
    15     int sum=0;
    16     while(x>0){
    17         sum+=c[x];
    18         x-=x&-x;
    19     }
    20     return sum;
    21 }
    22 int main(){
    23     int n;
    24     scanf("%d",&n);
    25     int MAX=-1;
    26     for(int i=1;i<=n;i++){
    27         scanf("%d",&a[i]);
    28         MAX=max(MAX,a[i]);
    29     }
    30     
    31     ll ans=0;
    32     for(int i=1;i<=n;i++){
    33         ans+=getsum(MAX)-getsum(a[i]);
    34         update(a[i]);
    35     }
    36     printf("%lld
    ",ans);
    37     return 0;
    38 }
    View Code

    Big Water Problem

    题解:线段数,树状数组都可以,现在想想直接前缀和不就好了。。。。。。。

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<cstdio>
     5 #define ll long long
     6 #define lson l,m,rt<<1
     7 #define rson m+1,r,rt<<1|1
     8 using namespace std;
     9 const int N =1e5+5;
    10 int n,m;
    11 ll val[4*N];
    12 int lazy[4*N];
    13 void pushup(int rt){
    14     val[rt]=val[rt<<1]+val[rt<<1|1];
    15 }
    16 void build(int l,int r,int rt){
    17     if(l==r){
    18         scanf("%lld",&val[rt]);
    19         return ;
    20     }
    21     int m=(l+r)>>1;
    22     build(l,m,rt<<1);
    23     build(m+1,r, rt<<1|1);
    24     pushup(rt);
    25 }
    26 void update(int x,int c,int l,int r,int rt){
    27     val[rt]+=c;
    28     int m=(l+r)>>1;
    29     if(l==r)return;
    30     if(m>=x)update(x,c,lson);
    31     else update(x,c,rson);
    32 }
    33 ll query(int L,int R,int l,int r,int rt){
    34     if(L<=l&&R>=r)return val[rt];
    35     ll ans=0;
    36     int m=(l+r)>>1;
    37     if(m>=L)ans+=query(L,R,lson);
    38     if(R>m)ans+=query(L,R,rson);
    39     return ans;
    40 }
    41 int main(){
    42     scanf("%d %d",&n,&m);
    43     build(1,n,1);
    44     while(m--){
    45         int x,l,r;
    46         scanf("%d%d%d",&x,&l,&r);
    47         if(x==1)update(l,r,1,n,1);
    48         else cout<<query(l,r,1,n,1)<<endl;
    49     }
    50     return 0;
    51 }
    View Code

    字符串的问题

    题解:KMP求出next数组,next数组就是最大匹配前后缀。设L为字符串长度则如果存在字符串中(不含两端)的子字符串和字符串的前后缀和相同,一定存在next[M]=next[L](0<M<L)

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 using namespace std;
     5 const int N =1e6+5;
     6 int n,m;
     7 int nx[N];
     8 char str[N];
     9 int num[N];
    10 int len;
    11 void getnx(){
    12     int j=0,k=-1;
    13     nx[0]=-1;
    14     while(j<len){
    15         if(k==-1||str[j]==str[k]){
    16             nx[++j]=++k;
    17         }
    18         else
    19             k=nx[k];
    20     }
    21 }
    22 int main(){
    23     scanf("%s",str);
    24     len=strlen(str);
    25     getnx();
    26     int l=nx[len];
    27     for(int i=1;i<len;i++){
    28         num[nx[i]]++;
    29     }
    30     bool flag=0;
    31     while(l){
    32         if(num[l]){
    33             for(int i=0;i<l;i++)cout<<str[i];
    34             flag=1;
    35             break;
    36         }
    37         l=nx[l];
    38     }
    39     if(!flag)cout<<"Just a legend
    ";
    40     return 0;
    41 }
    View Code

    集合问题

    题解:这题一开始我直接dfs一路找对应的数添加到集合中,结果TLE了。赛后后来看了别人的代码,用并查集来维护集合这个概念。

    #include<iostream>
    #include<map>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    const int N =1e5+5;
    int p[N];
    int fa[N];
    int find(int x){
        return fa[x]==x?x:find(fa[x]);
    }
    void unite(int x,int y){
        x=find(x);
        y=find(y);
        if(x!=y)fa[y]=x;
    }
    map<int,int>mp;
    int main(){
        int n,a,b;
        cin>>n>>a>>b;
        int MAX=-1;
        for(int i=1;i<=n;i++){
            scanf("%d",&p[i]);
            MAX=max(MAX,p[i]);
            mp[p[i]]=i;
        }
        if(MAX>max(a,b))cout<<"NO
    ";
        else {
            for(int i=0;i<=n+1;i++)fa[i]=i;
            for(int i=1;i<=n;i++){
                if(mp[a-p[i]])unite(i,mp[a-p[i]]);
                else unite(i,n+1);
                if(mp[b-p[i]])unite(i,mp[b-p[i]]);
                else unite(i,0);
            }
            int u=find(0);
            int v=find(n+1);
            if(u==v)printf("NO
    ");
            else {
                printf("YES
    ");
                for(int i=1 ;i<=n;i++){
                    if(i!=1)printf(" ");
                    int l=find(i);
                    if(l!=u)printf("1");
                    else printf("0");
                }
            }
        }
    }
    View Code

    情人节的电灯泡

    题解:一开始的思路是二维化一维直接做差来写,后来想想还是不对,因为矩形一维做差肯定会T掉,因为要对每一行都要做差。接着想到二维树状数组,但是忘了怎么写。。(待补)

      若要求黄色矩形内的亮灯个数,设黄色矩形左上角坐标为(a,b)则右下角为(c,d)。getsum(c,d)=黄色面积+绿色面积+红色面积-白色面积,因此黄色面积=getsum(c,d)-绿色面积-红色面积+白色面积=getsum(c,d)-getsum(c,b-1)-getsum(a-1,d)+getsum(a-1,b-1)

       

    #include<cstdio>
    using namespace std;
    const int N =1e3+5;
    int data[N][N];
    int sum[N][N];
    void Update(int x,int y,int c){
        for(int i=x;i<=N;i+=i&-i){
            for(int j=y;j<=N;j+=j&-j){
                sum[i][j]+=c;
            }
        }
    }
    int  getsum(int x,int y){
        int ans=0;
        for(int i=x;i>0;i-=i&-i)
            for(int j=y;j>0;j-=j&-j)
                ans+=sum[i][j];
        return ans;
    }
    int main(){
        int n,m;
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++){
                scanf("%d",&data[i][j]);
                if(data[i][j])Update(i,j,1);
            }
        while(m--){
            int f,x1,y1,x2,y2;
            scanf("%d %d %d",&f,&x1,&y1);
            if(f==1){
                if(data[x1][y1]==1)
                    Update(x1,y1,-1),data[x1][y1]=0;
                else
                    Update(x1,y1,1),data[x1][y1]=1;
            }
            else {
                scanf("%d %d",&x2,&y2);
                printf("%d
    ",getsum(x2,y2)+getsum(x1-1,y1-1)-getsum(x2,y1-1)-getsum(x1-1,y2));
            }
        }
        return 0;
    }
    View Code

    The Biggest Water Problem

    题解:水题。。

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 int main(){
     5     int n;
     6     scanf("%d",&n);
     7     int sum=0;
     8     while(1){
     9         while(n){
    10             sum+=n%10;
    11             n/=10;
    12         }
    13         if(sum/10==0)break;
    14         else{
    15             n=sum;
    16             sum=0;
    17         }
    18     }
    19     cout<<sum;
    20     return 0;
    21 }
    View Code

    送分啦-QAQ

    题解:斐波那契博弈。先手胜当且仅当n不是斐波那契数。 

     1 #include<iostream>
     2 using namespace std;
     3 const int N =1e5+5;
     4 ll a[N];
     5 int main(){
     6     fio;
     7     int n;
     8     cin>>n;
     9     a[1]=1;
    10     a[0]=1;
    11     int i;
    12     for( i=2;;i++){
    13        a[i]=a[i-1]+a[i-2];
    14         if(a[i]>=1000000000)break;
    15     }
    16     for(int j=0;j<=i;j++){
    17         if(a[j]==n)return cout<<"Sha"<<endl,0;
    18     }
    19     cout<<"Xian"<<endl;
    20     return 0;
    21 }
    View Code

    Tree Recovery

    题解:线段树区间更新+区间求和

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #define ll long long
     5 #define lson l,m,rt<<1
     6 #define rson m+1,r,rt<<1|1
     7 using namespace std;
     8 const int N =1e5+5;
     9 int n,m;
    10 ll val[4*N];
    11 ll lazy[4*N];
    12 void pushup(int rt){
    13     val[rt]=val[rt<<1]+val[rt<<1|1];
    14 }
    15 void build(int l,int r,int rt){
    16     if(l==r){
    17         scanf("%lld",&val[rt]);
    18         return ;
    19     }
    20     int m=(l+r)>>1;
    21     build(l,m,rt<<1);
    22     build(m+1,r,rt<<1|1);
    23     pushup(rt);
    24 }
    25 void pushdown(int l,int r,int rt){
    26     if(lazy[rt]){
    27         int m=(l+r)>>1;
    28         lazy[rt<<1]+=lazy[rt];
    29         lazy[rt<<1|1]+=lazy[rt];
    30         val[rt<<1]+=lazy[rt]*(m-l+1);
    31         val[rt<<1|1]+=lazy[rt]*(r-m);
    32         lazy[rt]=0;
    33     }
    34 }
    35 void update(int L,int R,int c,int l,int r,int rt){
    36     if(L<=l&&R>=r){
    37         lazy[rt]+=c;
    38         val[rt]+=1LL*c*(r-l+1);
    39         return ;
    40     }
    41     pushdown(l,r,rt);
    42     int m=(l+r)>>1;
    43     if(L<=m)update(L,R,c,lson);
    44     if(R>m) update(L,R,c,rson);
    45     pushup(rt);
    46 }
    47 ll query(int L,int R,int l,int r,int rt){
    48     if(L<=l&&R>=r){
    49        // cout<<val[rt]<<"   "<<rt<<endl;
    50         return val[rt];
    51     }
    52     pushdown(l,r,rt);
    53     ll ans=0;
    54     int m=(l+r)>>1;
    55     if(m>=L)ans+=query(L,R,lson);
    56     if(R>m)ans+=query(L,R,rson);
    57     return ans;
    58 }
    59 int main(){
    60     scanf("%d %d",&n,&m);
    61     build(1,n,1);
    62     while(m--){
    63         int l,r,c;
    64         char x[5];
    65         scanf("%s%d%d",x,&l,&r);
    66         if(x[0]=='C'){
    67             scanf("%d",&c);
    68             update(l,r,c,1,n,1);
    69         }
    70         else cout<<query(l,r,1,n,1)<<endl;
    71     }
    72     return 0;
    73 }
    View Code
  • 相关阅读:
    Android存储数据方式(转)
    Android实现双进程守护 (转)
    Android DOM、SAX、Pull解析XML(转)
    TCP/IP和Socket的关系(转)
    Socket通信原理和实践
    [转]Android中Intent传递对象的两种方法(Serializable,Parcelable)
    内存堆和栈的区别
    hdu 1754 线段树
    hdu 1166 线段树
    zoj 3686 线段树
  • 原文地址:https://www.cnblogs.com/Mrleon/p/8473757.html
Copyright © 2011-2022 走看看