Educational Codeforces Round 112 (Rated for Div. 2)

Educational Codeforces Round 112 (Rated for Div. 2)

A. Perfectly Imperfect Array

我是傻逼。卡了40分钟。大力猜错了。一开始想法是预处理120(6,8,10的公倍数)以内的最优解答案。然后对大于120的输入处理一下输出就好。结果WA了==。
考虑到无论那种方法每片披萨的代价一样,也就是说答案就是披萨片数乘2.5。于是只要找大于等于n的最小可拼凑整数即可。然后发现大于等于6的偶数都可以拼凑出来,于是对小于6的特判,大于等于6的,偶数直接乘2.5,奇数+1乘2.5。

ll aa[40005];

int main(){
    int t;
    cin>>t;
    while(t--){
        ll n;
        cin>>n;
        if(n<=6) cout<<15;
        else if(n&1) cout<<(n+1)/2*5;
        else cout<<n/2*5;
        cout<<'\n';
    }
}

B. Two Tables

首先把第一个桌子等价转化到靠右上角的位置,那么把二号桌子往左下角接触原点处塞绝对是最优的,一号桌子最优解肯定是只往上或往右平移,所以对两个方向求出需要移动的最小距离。如果一号桌子在两种情况都会越界,那么无解,否则就可以求出最小距离。

int xt,yt,x1,x2,y2,w1,h1,w2,h2,y3;

void change(){
    int tmp;
    if(y3<yt-y2){
        tmp=y3;
        y3=yt-y2;
        y2=yt-tmp;
    }
    if(x1<xt-x2){
        tmp=x1;
        x1=xt-x2;
        x2=xt-tmp;
    }
}

void solve(){
    cin>>xt>>yt;
    cin>>x1>>y3>>x2>>y2;
    w1=x2-x1; h1=y2-y3;
    cin>>w2>>h2;
    change();
   // cout<<'+'<<x1<<' '<<y3<<' '<<x2<<' '<<y2<<'\n';
    int ans=2e9;
    int up=-min(0,y3-h2),rig=-min(0,x1-w2);
   // cout<<'-'<<up<<' '<<rig<<'\n';
    if(up==0||rig==0) ans=0;
    else{
        if(y2+up<=yt) ans=min(ans,up);
        if(x2+rig<=xt) ans=min(ans,rig);
    }
    if(ans==2e9) cout<<-1<<'\n';
    else cout<<fixed<<setprecision(9)<<(double)ans<<'\n';
}

int main(){
    int t;
    cin>>t;
    while(t--)
        solve();
    return 0;
}

C. Coin Rows

容易想到无论A怎么走,B要么一直往右走到尽头,最后往下走,或,先往下走再往右走到尽头是最优的。A要尽可能缩小这个最优值。那么我们只需要对第一行处理后缀和,第二行处理前缀和,然后枚举列即可。

int aa[3][100005];

int main(){
    IOS;
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        for(int i=1;i<=2;++i){
            for(int j=1;j<=n;++j){
                cin>>aa[i][j];
            }
        }
        for(int j=1;j<=n;++j) aa[2][j]+=aa[2][j-1];
        for(int j=n;j>=1;--j) aa[1][j]+=aa[1][j+1];
        int mn=2e9;
        for(int i=1;i<=n;++i){
            if(max(aa[1][i+1], aa[2][i-1])<mn){
                mn=max(aa[1][i+1], aa[2][i-1]);
            }
        }
        fill(aa[1]+1,aa[1]+n+1,0);
        fill(aa[2]+1,aa[2]+n+1,0);
        cout<<mn<<'\n';
    }
    return 0;
}

D. Say No to Palindromes

A题被卡了,导致D没时间写了==。其实也简单。
我们试着构造题目要求的美丽字符串,发现只能形如:

  • abcabcabc...
  • acbacbacb...
  • bcabcabca...
  • ...

共计六种情况。那么我们把这六种情况分别与原串匹配,预处理出需要改变的前缀和。之后询问时直接输出六种情况的最小值就好。

string str;
int aa[200005][7];

int main(){
    string s[10];
    s[1]="abc",s[2]="acb",s[3]="bac",s[4]="bca",s[5]="cab",s[6]="cba";
    int n,m;
    cin>>n>>m>>str;
    for(int i=0;i<n;++i){5
        for(int j=1;j<=6;++j){
            aa[i+1][j]=aa[i][j];
            if(str[i]!=s[j][i%3]) ++aa[i+1][j];
        }
    }
    int l,r;
    while(m--){
        cin>>l>>r;
        cout<<min({aa[r][1]-aa[l-1][1],aa[r][2]-aa[l-1][2],aa[r][3]-aa[l-1][3],aa[r][4]-aa[l-1][4],aa[r][5]-aa[l-1][5],aa[r][6]-aa[l-1][6]});
        cout<<'\n';
    }
    return 0;
}

E. Boring Segments

头一次补到第五题,也说明这场比较简单。。。哎
给一个全为0的段,给很多个子段。。一眼就想到线段树啦。。。
首先想到最小的代价将序列全覆盖,但是全覆盖并不能保证从1可以走到n.
转化一下题目条件。
给定段[l, r],段内任何一点可以可以到达任何一点。可以转化为,给定段[l,r-1],段内和r任何一点可以到达[l, r]。这样可以把[l, r]转化为[l, r-1]。
想一下,原段长为n, 如果[1, n-1]都可以被转化后的段覆盖,那么1肯定是可以到n的。如果[1, n-1]中间有一个点没有被覆盖,那么1肯定是到不了n的。
我们只关心[1,n-1]是否被覆盖, 那么我们用线段树维护这个区间即可。

但是代价是所选择的子段的价值之差的绝对值的最小值。那么从小到达排序,从小到大调,如果每个时刻被[1, n-1]被完全覆盖了,那么就从小到大弹出字段知道没有被完全覆盖...总之是个贪心的想法。证明不难。

就线段树而言我们维护的是最小值。由于存在着区间修改,所以要用lazytag。

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pr;
const ll MAXN=1e18;
const int MOD=1e6;

struct Tree{
    #define lchild rt<<1
    #define rchild rt<<1|1
    int date[4000005];
    int tag[4000005];
    void push_down(int rt){
        date[lchild]+=tag[rt];
        date[rchild]+=tag[rt];
        tag[lchild]+=tag[rt];
        tag[rchild]+=tag[rt];
        tag[rt]=0;
    }
    void push_up(int rt){
        date[rt]=min(date[lchild],date[rchild]);
    }
    void update(int rt, int lef,int rig, int L, int R, int c){
        if(lef>=L&&rig<=R){
            date[rt]+=c;
            tag[rt]+=c;
            return;
        }
        push_down(rt);
        int mid=(lef+rig)>>1;
        if(mid>=L) update(lchild, lef, mid, L, R, c);
        if(mid+1<=R) update(rchild, mid+1, rig, L, R, c); 
        push_up(rt);
    }
    int query(int rt, int lef, int rig, int L, int R){
        if(lef>=L&&rig<=R){
            return date[rt];
        }
        push_down(rt);
        int mid=(lef+rig)>>2;
        int ans=2e9;
        if(mid>=L) ans=min(ans, query(lchild, lef, mid, L, R));                 
        if(mid+1<=R) ans=min(ans, query(rchild, mid+1, rig, L, R));
        return ans;
    }
}tree;

struct NODE{
    int lef,rig,w;
}aa[300005];

bool cmp(NODE &a, NODE &b){
    return a.w<b.w;
}

int main(){
    int n,m;
    cin>>m>>n;
    --n;
    for(int i=1;i<=m;++i){
        cin>>aa[i].lef>>aa[i].rig>>aa[i].w;
        --aa[i].rig;
    }
    sort(aa+1, aa+1+m, cmp);
    int pos=0,ans=2e9;
    for(int i=1;i<=m;++i){
        tree.update(1, 1, n, aa[i].lef, aa[i].rig, 1);
        if(tree.date[1]){
            while(tree.date[1]){
                ++pos;
                tree.update(1, 1, n, aa[pos].lef, aa[pos].rig, -1);
                
            }
            ans=min(ans, aa[i].w-aa[pos].w);
        }
    }
    cout<<ans<<'\n';
    return 0;
}
posted @ 2021-08-01 00:08  七铭的魔法师  阅读(65)  评论(0编辑  收藏  举报