2018年全国多校算法寒假训练营练习比赛(第五场)

比赛t题目链接:

                https://www.nowcoder.com/acm/contest/77#question

A .逆序数

           思路:直接用分治法求逆序数即可,这里也可以用树状数组求,数据也不大。所以不用离散求处理下输入0即可。

            附上两个不同版本的代码:

            分治:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int num[100005],c[100005];
ll ans ;
void margeHe(int S,int mid,int E){
    int s=S,m = mid+1,cnt = s;
    while(s<=mid&&m<=E){
        if(num[s]<=num[m]){
            c[cnt++] = num[s++];
        }
        else{
            c[cnt++] = num[m++];
            ans+=mid-s+1;
        }
    }
    while(s<=mid){
        c[cnt++] = num[s++];
    }
    while(m<=E){
        c[cnt++] = num[m++];
    }
    for(int i=S;i<=E;i++){
        num[i] = c[i];  //合并过程排好序
    }
}

void marge(int S,int E){
    if(S>=E) return ;
    int mid = (S+E)>>1;
    marge(S,mid);
    marge(mid+1,E);
    margeHe(S,mid,E);
}
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>num[i];
    ans = 0;
    marge(1,n);
    cout<<ans<<endl;
    return 0;
}

            树状数组:

#include <iostream>
#include <cstring>
using namespace std;
#define N 500005
typedef long long ll;
int c[N];
int n;
ll lowbit(ll i)
{
    return i&(-i);
}
ll insert(ll i,ll x)
{
    while(i<=n&&i!=0){
        c[i]+=x;
        i+=lowbit(i);
    }
    return 0;
}
 
ll getsum(ll i)
{
    ll sum=0;
    while(i>0){
        sum+=c[i];
        i-=lowbit(i);
    }
    return sum;
}
  
int main()
{
    while(cin>>n){
        ll ans=0;
        memset(c,0,sizeof(c));
        ll cnt = 0;
        for(int i=1;i<=n;i++){
            int a;
            cin>>a;
            insert(a,1);
            if(a==0){
                ++cnt;  //注意处理0输入即可
                ans +=i-cnt;
            }
            else
                ans+=i-(getsum(a)+cnt);//统计当前序列中大于a的元素的个数
        }
        cout<<ans<<endl;
    }
    return 0;
}

B.Big Water Problem

        思路:裸的树状数组,裸的单点修改和区间查询(QAQ!!据说可以暴力????

        代码:

        

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5+11;
typedef long long ll;
int sum ;
int n,m;
ll tree[maxn];
int lowbit(int t)
{
    return t&(-t);
}
void add(int x,int y)
{
    for(int i=x;i<=n;i+=lowbit(i))
        tree[i]+=y;

}
ll getsum(int x)
{
    ll ans=0;
    for(int i=x;i>0;i-=lowbit(i))
        ans+=tree[i];
    return ans;
}
ll getqujiansum(int x1,int x2){
    return getsum(x2)-getsum(x1-1);
}
int main(){
    int a;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a;
        add(i,a);
    }
    int x,y;
    for(int i=0;i<m;i++){
        cin>>a;
        if(a==1){
            cin>>x>>y;
            add(x,y);
        }
        if(a==2){
            cin>>x>>y;
            cout<<getqujiansum(x,y)<<endl;
        }
    }

    return 0;
}

C.字符串问题

            思路:先预处理next数组,得到输入字符串的前后缀关系,并开另一数组记录关系,从next数组最后即串

的长度+1开始往回回溯看是否满足条件即可.(一拿题想多了。。。其实可能存在多个字串满足,我们根据

next数组就能找到其中一个即可。)。还是不明白的,输出next数组找找思路.

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int maxn = 1000010;
char s[maxn];
int nxt[maxn];
int mark[maxn];
void get_next(int len)
{
    int i = 0, j = -1;
    nxt[0] = -1;
    while (i < len)
    {
        if (j == -1 || s[i] == s[j])
            nxt[++i] = ++j;
        else j = nxt[j];
    }

}
int main()
{
    cin>>s;
    int len = strlen(s);
    memset(mark,0,sizeof(mark));
    get_next(len);
    for(int i=0;i<len;i++){
        mark[nxt[i]]++;
    }
    int i = nxt[len];
    bool flag = 1;
    while (i)
    {
        if (mark[i]) {
            for (int j = 0; j < i; j++)
                cout<<s[j];
            cout<<endl;
            flag = 0;
            break;
        }
        i = nxt[i];
    }
    if(flag)
        cout<<"Just a legend"<<endl;

}


D.集合问题

            小编太弱了,没做道这题,看了题解,菊苣用并查集...不过从后面读了下题,感觉能够用开两个vector+二分能做???过后补题试试..


E.情人节的电灯泡

            思路:二维树状数组的单点修改,区间查询,直接上代码 (暴力居然能过,再也不相信数据水到这程度...)

            

#include <bits/stdc++.h>
using namespace std;
int n,q;
int num[1005][1005],tree[1005][1005];
int lowbit(int t){
    return t&(-t);
}
void add(int x,int y,int val){
    for(int i=x;i<=n;i+=lowbit(i)){
        for(int j=y;j<=n;j+=lowbit(j)){
            tree[i][j] +=val;
        }
    }

}
int getsum(int x,int y){
    int sum = 0;
    for(int i=x;i>0;i-=lowbit(i)){
        for(int j=y;j>0;j-=lowbit(j)){
            sum+=tree[i][j];
        }
    }
    return sum;
}
int main(){


    int a,x,y,x1,x2,y1,y2;
    cin>>n>>q;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cin>>num[i][j];
            if(num[i][j]){
                add(i,j,1);
            }
        }
    }

    for(int i=1;i<=q;i++){
        cin>>a;
        if(a==1){
            cin>>x>>y;
            if(num[x][y]){
                add(x,y,-1);
            }else{
                add(x,y,1);
            }
            num[x][y]^=1;
        }
        if(a==2){
            cin>>x1>>y1>>x2>>y2;
            cout<<getsum(x2,y2)-getsum(x1-1,y2)-getsum(x2,y1-1)+getsum(x1-1,y1-1)<<endl;
        }
    }
    return 0;
}


 F .The Biggest Water Problem

 签到题

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+11;
int sum ;
int ji(int su){
    sum = 0;
    while(su){
        int t = su%10;
        su /=10;
        sum+=t;
    }
    if(sum<10) return sum;
    else ji(sum);
    return sum;

}
int main(){
    int su;
    cin>>su;
    cout<<ji(su)<<endl;

    return 0;
}

   G 送分啦-QAQ

    思路:斐波那序博弈(不会博弈的,要好好了解博弈...

#include <iostream>
#include <stdio.h>
using namespace std;
typedef long long ll;
ll fib[1000];
ll ans;
void init(){
    fib[0] = 1;
    fib[1] = 1;
    for(int i=2;i<=1000;i++){
        fib[i] = fib[i-1]+fib[i-2];
    }
}


int main()
{
    int n;
    init();
     
    cin>>n;
    int i;
    for(i=0;i<45;i++){
        if(fib[i]==n) break;
    }
    if(i<45){
        cout<<"Sha"<<endl;
    }
    else
        cout<<"Xian"<<endl;

    return 0;
}

    H Tree Recovery  

    思路: 裸的线段树 (据说 暴力优化下也能过,哎 感觉最后一场暴力场?吐槽小数据。。。

    

#include <bits/stdc++.h>
using namespace std;
int n,q;
#define maxn 100007
int Sum[maxn<<2],Add[maxn<<2];
int A[maxn];
 
void PushUp(int rt){Sum[rt]=Sum[rt<<1]+Sum[rt<<1|1];}
 
void PushDown(int rt,int ln,int rn){  //下推标记
     
    if(Add[rt]){
         
        Add[rt<<1]+=Add[rt];
        Add[rt<<1|1]+=Add[rt];
         
        Sum[rt<<1]+=Add[rt]*ln;
        Sum[rt<<1|1]+=Add[rt]*rn;
        
        Add[rt]=0;
    }
}
void Build(int l,int r,int rt){   
    if(l==r) { 
        Sum[rt]=A[l]; 
        return;
    }
    int m=(l+r)>>1;
  
    Build(l,m,rt<<1);
    Build(m+1,r,rt<<1|1);
    
    PushUp(rt);
}
void Update(int L,int R,int C,int l,int r,int rt){   
    if(L <= l && r <= R){ 
        Sum[rt]+=C*(r-l+1); 
        Add[rt]+=C;  
        return ;
    }
    int m=(l+r)>>1;
    PushDown(rt,m-l+1,r-m); 
     
    if(L <= m) Update(L,R,C,l,m,rt<<1);
    if(R >  m) Update(L,R,C,m+1,r,rt<<1|1);
    PushUp(rt); 
}

int Query(int L,int R,int l,int r,int rt){   
    if(L <= l && r <= R){
       
        return Sum[rt];
    }
    int m=(l+r)>>1;
    
    PushDown(rt,m-l+1,r-m);

     
    int ANS=0;
    if(L <= m) ANS+=Query(L,R,l,m,rt<<1);
    if(R >  m) ANS+=Query(L,R,m+1,r,rt<<1|1);
    return ANS;
}
int main(){


    cin>>n>>q;
    for(int i=1;i<=n;i++){
        cin>>A[i];
    }
    Build(1,n,1);
    int x,y,ad;
    char a;
    for(int i=1;i<=q;i++){
        cin>>a;
        if(a=='Q'){
            cin>>x>>y;
            cout<<Query(x,y,1,n,1)<<endl;
        }
        if(a=='C'){
            cin>>x>>y>>ad;
            Update(x,y,ad,1,n,1);
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值