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
原文地址:https://www.cnblogs.com/Mrleon/p/8473757.html