Codeforces Round #353 (Div. 2)题解

来源:互联网 发布:多益网络账号注册 编辑:程序博客网 时间:2024/05/21 10:04

比赛传送门:http://codeforces.com/contest/675

A:水题

判断是否在等差数列里,一定要分类讨论公差正负,b和a的大小,不能直接模


B:水题

5个位置变量设为x1到x5,发现4个正方形里都有x3,所以x3是有n种取法,接下来就是x1取定,另外3个都取定了,算出另外3个由x1表达的式子,判断是否在范围里即可


C:前缀和

给你n个数字,围成一个圈,然后总和为0,有一种操作是可以把一个数字,给周围两个数字中的一个一些值,就比如有-3 和3,3能给-3 3这么多值,然后他们就变成了0 0,这是一次操作,然后问你最少多少次操作,能变成全0

考虑一段值,和为0,他们变成全0,只需要长度-1次操作,这是肯定的,所以就是找出那些和为0的段

这个该怎么找呢,可以把前缀和都求出来,这样一段长度为n的前缀和数组,里面有些是0有些不是0,不是0都是成段出现,这连续的段的长度就是这一段需要移动的次数,所以只需要考虑长度n的前缀和数组里面不是0的个数

但是这n个数字是一个圈,所以不一定是从1开始到n,可能2到n+1之类的,所以需要把长度n补为2n,然后在里面考虑长度n的前缀和,当你考虑2到n+1的时候,应该找里面不为sum[1]的个数,因为这个前缀和是要减去sum[1]的

#include <map>#include <set>#include <stack>#include <queue>#include <cmath>#include <string>#include <vector>#include <cstdio>#include <cctype>#include <cstring>#include <sstream>#include <cstdlib>#include <iostream>#include <algorithm>#pragma comment(linker,"/STACK:102400000,102400000")using namespace std;#define   MAX           200005#define   MAXN          1000005#define   maxnode       15#define   sigma_size    30#define   lson          l,m,rt<<1#define   rson          m+1,r,rt<<1|1#define   lrt           rt<<1#define   rrt           rt<<1|1#define   middle        int m=(r+l)>>1#define   LL            long long#define   ull           unsigned long long#define   mem(x,v)      memset(x,v,sizeof(x))#define   lowbit(x)     (x&-x)#define   pii           pair<int,int>#define   bits(a)       __builtin_popcount(a)#define   mk            make_pair#define   limit         10000//const int    prime = 999983;const int    INF   = 0x3f3f3f3f;const LL     INFF  = 0x3f3f;const double pi    = acos(-1.0);const double inf   = 1e18;const double eps   = 1e-8;const LL    mod    = 1e9+7;const ull    mx    = 133333331;/*****************************************************/inline void RI(int &x) {      char c;      while((c=getchar())<'0' || c>'9');      x=c-'0';      while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; }/*****************************************************/map<LL,int> ma;int a[MAX];LL sum[MAX];int main(){    //freopen("in.txt","r",stdin);    int n;    while(cin>>n){        ma.clear();        sum[0]=0;        for(int i=1;i<=n;i++) scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i];        for(int i=n+1;i<=2*n;i++) sum[i]=sum[i-1]+a[i-n];        for(int i=1;i<=n;i++){            if(!ma.count(sum[i])) ma[sum[i]]=0;            ma[sum[i]]++;        }        int maxn=ma[0];        for(int i=n+1;i<=2*n;i++){            ma[sum[i-n]]--;            ma[sum[i]]++;            maxn=max(maxn,ma[sum[i-n]]);        }        cout<<n-maxn<<endl;    }    return 0;}


D:排序+set

构造二叉搜索树,问你按照顺序放进去每个节点,它的父节点是什么

暴力肯定会TLE辣,如果是一条链,就退化到O(n^2)了

要考虑二叉搜索树的性质,把一棵二叉搜索树投影到横轴上,数列是有序的,所以可以先排序,然后按照顺序往里面放,记录每个点的左右儿子是否都已经被占领即可,每次放进去的时候找比它小的第一个和比它大的第一个就行,然后考虑比它小的的右儿子,比它大的的左儿子,必定只有一个满足(因为小的放进去,已经占领了大的左儿子,或者大的放进去占领了小的右儿子,所以必定只有一个解)

#include <map>#include <set>#include <stack>#include <queue>#include <cmath>#include <string>#include <vector>#include <cstdio>#include <cctype>#include <cstring>#include <sstream>#include <cstdlib>#include <iostream>#include <algorithm>#pragma comment(linker,"/STACK:102400000,102400000")using namespace std;#define   MAX           100005#define   MAXN          1000005#define   maxnode       15#define   sigma_size    30#define   lson          l,m,rt<<1#define   rson          m+1,r,rt<<1|1#define   lrt           rt<<1#define   rrt           rt<<1|1#define   middle        int m=(r+l)>>1#define   LL            long long#define   ull           unsigned long long#define   mem(x,v)      memset(x,v,sizeof(x))#define   lowbit(x)     (x&-x)#define   pii           pair<int,int>#define   bits(a)       __builtin_popcount(a)#define   mk            make_pair#define   limit         10000//const int    prime = 999983;const int    INF   = 0x3f3f3f3f;const LL     INFF  = 0x3f3f;const double pi    = acos(-1.0);const double inf   = 1e18;const double eps   = 1e-8;const LL    mod    = 1e9+7;const ull    mx    = 133333331;/*****************************************************/inline void RI(int &x) {      char c;      while((c=getchar())<'0' || c>'9');      x=c-'0';      while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; }/*****************************************************/set<int> s;map<int,int> l,r;int main(){    //freopen("in.txt","r",stdin);    int n;    while(cin>>n){        l.clear(),r.clear();s.clear();        for(int i=0;i<n;i++){            int a;            scanf("%d",&a);            if(i){                set<int>::iterator L=s.lower_bound(a);                set<int>::iterator R=s.lower_bound(a);                if(L==s.begin()){                    printf("%d",*R);                    l[*R]=a;                }                else if(R==s.end()){                    L--;                    printf("%d",*L);                    r[*L]=a;                }                else{                    L--;                    if(r[*L]){                        printf("%d",*R);                        l[*R]=a;                    }                    else{                        printf("%d",*L);                        r[*L]=a;                    }                }            }            s.insert(a);            if(i){                if(i==n-1) printf("\n");                else printf(" ");            }        }    }    return 0;}

E:dp+线段树

给你第i个车站,可以买到i+1到ai的车站的票,p[i,j]为从i到j的用的最少的车票,问你sigma(p[i,j])

考虑p[i]为第i个车站往后面的所有车站走的最小值,能直接到i+1到ai,所以i+1 - ai之间的车站肯定是1次就能到达,后面的那些车站如何最小化呢,应该要在i+1 - ai之间找一个过渡点,哪个最优呢,我原本考虑是p[i]最小的,但是发现并不行,因为p[i]最小,不代表去掉i能1次到达的那些站之后还是最小,所以应该考虑区间里面能到达最远地方的那个车站,因为它能走的最远,它用一次票走到的地方更多,所以它最优,线段树维护下即可

#include <map>#include <set>#include <stack>#include <queue>#include <cmath>#include <string>#include <vector>#include <cstdio>#include <cctype>#include <cstring>#include <sstream>#include <cstdlib>#include <iostream>#include <algorithm>#pragma comment(linker,"/STACK:102400000,102400000")using namespace std;#define   MAX           100005#define   MAXN          1000005#define   maxnode       15#define   sigma_size    30#define   lson          l,m,rt<<1#define   rson          m+1,r,rt<<1|1#define   lrt           rt<<1#define   rrt           rt<<1|1#define   middle        int m=(r+l)>>1#define   LL            long long#define   ull           unsigned long long#define   mem(x,v)      memset(x,v,sizeof(x))#define   lowbit(x)     (x&-x)#define   pii           pair<int,int>#define   bits(a)       __builtin_popcount(a)#define   mk            make_pair#define   limit         10000//const int    prime = 999983;const int    INF   = 0x3f3f3f3f;const LL     INFF  = 0x3f3f;const double pi    = acos(-1.0);const double inf   = 1e18;const double eps   = 1e-8;const LL    mod    = 1e9+7;const ull    mx    = 133333331;/*****************************************************/inline void RI(int &x) {      char c;      while((c=getchar())<'0' || c>'9');      x=c-'0';      while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; }/*****************************************************/LL p[MAX];pii maxv[MAX<<2];int a[MAX];void pushup(int rt){    maxv[rt]=max(maxv[rrt],maxv[lrt]);}void build(int l,int r,int rt){    if(l==r){        maxv[rt]=mk(0,l);        return;    }    middle;    build(lson);    build(rson);}void update(int l,int r,int rt,int pos,int d){    if(l==r){        maxv[rt]=mk(d,pos);        return ;    }    middle;    if(pos<=m) update(lson,pos,d);    else update(rson,pos,d);    pushup(rt);}pii query(int l,int r,int rt,int L,int R){    if(L<=l&&r<=R) return maxv[rt];    middle;    pii u=mk(0,0);    if(L<=m) u=max(u,query(lson,L,R));    if(R>m) u=max(u,query(rson,L,R));    return u;}int main(){    //freopen("in.txt","r",stdin);    int n;    while(cin>>n){        for(int i=1;i<n;i++) scanf("%d",&a[i]);        p[n-1]=1;        build(1,n,1);        update(1,n,1,n-1,a[n-1]);        LL ans=p[n-1];        for(int i=n-2;i>0;i--){            pii u=query(1,n,1,i+1,a[i]);            p[i]=a[i]-i+(p[u.second]-(a[i]-u.second))+(n-a[i]);            update(1,n,1,i,a[i]);            ans+=(LL)p[i];        }        cout<<ans<<endl;    }    return 0;}


0 0
原创粉丝点击