• 冬季训练8 AB题题解


    A题 

    题目大意:给出一个1~n的排列,现在要求选择一个合适的分割点,将整个排列分为两个部分,要求通过适当的移动使得前半部分的所有数值都小于后半部分的数值,现在给出移动每个数字所花费的代价,输出最小代价

    这题显然对于左集合若最后的个数为k,那值必定为1-k,右集合值为k+1-n;所以最朴素的方法就是枚举每个分割点,再枚举左集合的k值,再O(n)遍历出需要转移的价值,取min,复杂度O(n3)

    思考一下如果我们处理出权值从1到n的转移价值前缀和,当分割点从左往右移的过程中,若右区间划分出来的值为a[i],即当你枚举的k<a[i],对于前一次划分,你需要多承担将a[i]移到右集合的价值,对于k>a[i]的情况你可以少承担从右集合移到左集合的价值,可以将值O(1)转移,O(n2);

    在思考一下线段树维护每个k点当前划分的值,区间更新划分的影响全局取min,复杂度O(nlogn);

    
    
     1 #include<stdio.h>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<cstring>
     5 #include<algorithm>
     6 #include<bitset>
     7 #include<set>
     8 #include<deque>
     9 #include<queue>
    10 #include<vector>
    11 //#include<unordered_map>
    12 #include<map>
    13 #include<stack>
    14 using namespace std;
    15 #define ll long long
    16 #define ull unsigned long long
    17 #define pii pair<int,int>
    18 #define Pii pair<ll,ll>
    19 #define m_p make_pair
    20 #define l_b lower_bound
    21 #define u_b upper_bound 
    22 const int inf=0x3f3f3f3f;
    23 const ll linf=0x3f3f3f3f3f3f3f3f;
    24 const int maxn=2e5+11;
    25 const int maxm=1e3+11;
    26 const int mod=1e9+7; 
    27 inline ll rd() {ll res, ch=0;while(!(ch>='0'&&ch<='9')) ch=getchar();res=ch-'0';while((ch=getchar())>='0'&&ch<='9')res=res*10+ch-'0';return res;}
    28 inline ll qpow(ll a,ll b){ll res=1;while(b){if(b&1){res*=a;res%=mod;}b>>=1;a=a*a%mod;}return res;}
    29 inline ll gcd(ll a,ll b){if(b==0) return a;return gcd(b,a%b);}
    30 //iterator 
    31 //head
    32 ll tree[maxn<<2],lazy[maxn<<2];
    33 ll sum[maxn],a[maxn],b[maxn];
    34 inline ll read() {
    35     ll res, ch=0;
    36     while(!(ch>='0'&&ch<='9')) ch=getchar();
    37     res=ch-'0';
    38     while((ch=getchar())>='0'&&ch<='9')
    39         res=res*10+ch-'0';
    40     return res;
    41 }
    42 void pushdown(int rt) {
    43     if(lazy[rt]) {
    44         tree[rt<<1]+=lazy[rt];
    45         tree[rt<<1|1]+=lazy[rt];
    46         lazy[rt<<1]+=lazy[rt];
    47         lazy[rt<<1|1]+=lazy[rt];
    48         lazy[rt]=0;
    49     }
    50 }
    51 void build(int rt,int l,int r) {
    52     lazy[rt]=0;
    53     if(l==r) {
    54         tree[rt]=sum[l];
    55         return;
    56     }
    57     int mid=l+r>>1;
    58     build(rt<<1,l,mid);
    59     build(rt<<1|1,mid+1,r);
    60     tree[rt]=min(tree[rt<<1],tree[rt<<1|1]);
    61 }
    62 void update(int rt,int l,int r,int tl,int tr,int k) {
    63     if(l==tl&&r==tr) {
    64         lazy[rt]+=k;
    65         tree[rt]+=k;
    66         return;
    67     }
    68     pushdown(rt);
    69     int mid=l+r>>1;
    70     if(mid>=tr) {
    71         update(rt<<1,l,mid,tl,tr,k);
    72     } else if(tl>mid) {
    73         update(rt<<1|1,mid+1,r,tl,tr,k);
    74     } else {
    75         update(rt<<1,l,mid,tl,mid,k);
    76         update(rt<<1|1,mid+1,r,mid+1,tr,k);
    77     }
    78     tree[rt]=min(tree[rt<<1],tree[rt<<1|1]);
    79 }
    80 int main() {
    81     int n=read();
    82     for(int i=1; i<=n; i++) a[i]=read();
    83     for(int i=1; i<=n; i++) {
    84         b[i]=read();
    85         sum[a[i]]=b[i];
    86     }
    87     for(int i=2; i<=n; i++) sum[i]+=sum[i-1];
    88     build(1,1,n);
    89     ll ans=min(b[1],b[n]);
    90     for(int i=1; i<n; i++) {
    91         if(a[i]!=1) update(1,1,n,1,a[i]-1,b[i]);
    92         update(1,1,n,a[i],n,-b[i]);
    93         ans=min(ans,tree[1]);
    94     }
    95     printf("%lld
    ",ans);
    96 }
     

    B题

    在前面开m个0,学到了

    https://blog.csdn.net/weixin_44178736/article/details/104009340

    菜鸡不会树状数组,附送大家一份权值线段树代码

    还有莫队的解法大家自行百度

    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=6e5+11;
    struct Tree {
        int l,r,val;
    } tree[maxn<<2];
    int l[maxn],r[maxn],pos[maxn],a[maxn];
    int n,m;
    void pushup(int rt) {
        tree[rt].val=tree[rt<<1].val+tree[rt<<1|1].val;
    }
    void build(int rt,int l,int r) {
        tree[rt].l=l;
        tree[rt].r=r;
        if(l==r) {
            if(l>m) tree[rt].val=1;
            else tree[rt].val=0;
            return;
        }
        int mid=l+r>>1;
        build(rt<<1,l,mid);
        build(rt<<1|1,mid+1,r);
        pushup(rt);
    }
    void update(int rt,int p,int f) {
        if(tree[rt].l==tree[rt].r) {
            if(!f) tree[rt].val=0;
            else tree[rt].val=1;
            return;
        }
        int mid=tree[rt].l+tree[rt].r>>1;
        if(p<=mid) {
            update(rt<<1,p,f);
        } else update(rt<<1|1,p,f);
        pushup(rt);
    }
    void query(int rt,int now,int p,int x) {
        if(tree[rt].l==tree[rt].r) {
            r[x]=max(r[x],now+1);
            return;
        }
        int mid=tree[rt].l+tree[rt].r>>1;
        if(mid<p) {
            now+=tree[rt<<1].val;
            query(rt<<1|1,now,p,x);
        } else query(rt<<1,now,p,x);
    }
    int main() {
        cin>>n>>m;
        for(int i=1; i<=n; i++) pos[i]=i+m,l[i]=i,r[i]=i;
        int pre=m;
        for(int i=1; i<=m; i++) cin>>a[i];
        build(1,1,n+m);
        for(int i=1; i<=m; i++) {
            l[a[i]]=1;
            query(1,0,pos[a[i]],a[i]);
            //r[a[i]]=max(r[a[i]],pos[a[i]]-m);
            update(1,pos[a[i]],0);
            update(1,pre,1);
            pos[a[i]]=pre;
            pre--;
        }
        for(int i=1; i<=n; i++) query(1,0,pos[i],i);
        for(int i=1; i<=n; i++) cout<<l[i]<<' '<<r[i]<<endl;
    }
  • 相关阅读:
    Spring.NET学习笔记
    开源项目地址
    委托的实现匿名函数和朗姆达表达式
    c#事件与委托
    c# 时间戳转换
    List 排序
    DDD的好文章
    【转】理解JMeter聚合报告(Aggregate Report)
    【转】JMeter 通过 JDBC 访问 Oracle 和 MySQL
    【转】使用JMeter测试你的EJB
  • 原文地址:https://www.cnblogs.com/tinkerx/p/12262946.html
Copyright © 2020-2023  润新知