冬季训练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\n",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;
}

 

posted @ 2020-02-05 11:34  Tinker1998  阅读(149)  评论(0编辑  收藏  举报