AtCoder Regular Contest 103

AtCoder Regular Contest 103

一些吐槽

参加的第一场\(ARC\):一个模拟 + 三个构造
没见过比这更令人感动的题型设置了(简直就是针对我(TAT)) 。
感觉全场就我一个人\(E\)题WA了四遍才过.......

C-////

题目大意:
网址
给定一个串\(S\),要求修改一些字符,使得串满足以下条件:

  • \(S_i = S_{i+2}\)
  • \(S_1 \neq S_2\) 。

问最少需要修改多少个字符。
题解:
无脑统计一下奇数和偶数格的每种种类。
然后在最大值和次大值中进行抉择即可,各种情况讨论一下就行了。
代码:

#include<bits/stdc++.h>
#define IL inline
#define _ 200005
#define ll long long
using namespace std ;

IL int gi(){
    int data = 0 , m = 1; char ch = 0;
    while(ch!='-' && (ch<'0'||ch>'9')) ch = getchar();
    if(ch == '-'){m = 0 ; ch = getchar() ; }
    while(ch >= '0' && ch <= '9'){data = (data<<1) + (data<<3) + (ch^48) ; ch = getchar(); }
    return (m) ? data : -data ;
}

map<int,int>M[2] ;
struct Item{
    int val , cnt ;
    bool operator < (const Item &B) const {
        return (cnt ^ B.cnt) ? cnt > B.cnt : val > B.val ;
    }
}p[2][_] ;
int n , A[_] , tot[2] , n1 , n0 , ans ; 

int main() {
    freopen("testdata.in","r",stdin) ;
    n = gi() ;
    for(int i = 1; i <= n; i ++) A[i] = gi() ;
    for(int i = 1; i <= n; i += 2) {
        M[0][A[i]] ++ ; n0 ++ ;
    }
    for(int i = 2; i <= n; i += 2) {
        M[1][A[i]] ++ ; n1 ++ ;
    }
    int p1 , p2 ;
    for(map<int,int>::iterator it = M[0].begin(); it != M[0].end(); it ++) {
        p[0][++tot[0]].val = it->first ;
        p[0][tot[0]].cnt = it->second ;
    }
    for(map<int,int>::iterator it = M[1].begin(); it != M[1].end(); it ++) {
        p[1][++tot[1]].val = it->first ;
        p[1][tot[1]].cnt = it->second ;
    }
    sort(p[0] + 1 , p[0] + tot[0] + 1) ;
    sort(p[1] + 1 , p[1] + tot[1] + 1) ;
    if(tot[0] == 1 && tot[1] == 1) {
        if(p[0][1].val == p[1][1].val) ans = min(n0 , n1) ;
        else ans = 0 ;
    }
    else if(tot[0] == 1) {
        if(p[0][1].val == p[1][1].val) {
            ans = min(1 + n1 - p[1][1].cnt , n1 - p[1][2].cnt) ;
        }
        else ans = n1 - p[1][1].cnt ;
    }
    else if(tot[1] == 1) {
        if(p[1][1].val == p[0][1].val) {
            ans = min(1 + n0 - p[0][1].cnt , n0 - p[0][2].cnt) ;
        }
        else ans = n0 - p[0][1].cnt ;
    }
    else {
        if(p[1][1].val == p[0][1].val)
            ans = min(n1 - p[1][1].cnt + n0 - p[0][2].cnt , n0 - p[0][1].cnt + n1 - p[1][2].cnt) ;
        else ans = n1 - p[1][1].cnt + n0 - p[0][1].cnt ;
    }
    cout << ans << endl ;
    return 0 ;
}

D-Robot Arms

网址
题目大意:
给定平面上的\(n\)个点,要求构造\(m\)个数\(d_1,d_2...d_m\),需满足:
移动原则:从原点出发,走\(m\)步,每次可以向 上/下/左/右 走\(d_i\) 。
要求\(n\)个点都可以用 构造出的\(m\)个\(d\)通过上述方式到达。
其中构造结果有限制:\(m \leq 40\) , \(d \leq 10^{12}\),无解输出\(-1\)。
题解:
若\(n\)个点需要移动的步数奇偶性不同显然无解。
有个结论:用\(2^0,2^1...2^k\) 可以构造出\(2^{k+1}-1\)范围内的所有奇数。
若需要步数为偶数,我们强行开始时移动一步,把其变为奇数的情况。
把坐标系\(45\)度翻转,然后就只需要考虑一维了。
根据上面的结论,\(d=2^0,2^1...2^{33}\),每次贪心移动到离原点较近的点即可。
代码:

#include<bits/stdc++.h>
#define IL inline
#define _ 1005
#define ll long long
using namespace std ;

IL ll gi(){
    ll data = 0 , m = 1; char ch = 0;
    while(ch!='-' && (ch<'0'||ch>'9')) ch = getchar();
    if(ch == '-'){m = 0 ; ch = getchar() ; }
    while(ch >= '0' && ch <= '9'){data = (data<<1) + (data<<3) + (ch^48) ; ch = getchar(); }
    return (m) ? data : -data ;
}

ll X[_],Y[_],dis[_],n,m,mx[_],my[_] ;
vector<ll>Arm ;
vector<char>Ans[_] ;

namespace cpp600{
    IL void main() {
        m = 0 ;
        if(dis[1] % 2 == 0) {
            for(int i = 1; i <= n; i ++) {
                Ans[i].push_back('R') ; X[i] -- ;
            }
            m ++ ; Arm.push_back(1) ;
        }
        for(int i = 1; i <= n; i ++) X[i] = 2ll * X[i] , Y[i] = 2ll * Y[i] ;
        for(int i = 1; i <= n; i ++) {
            ll x = X[i] , y = Y[i] ;
            X[i] = x + y ; Y[i] = x - y ;
            X[i] >>= 1 ; Y[i] >>= 1 ;
        }
        //for(int i = 1; i <= n; i ++) cout << X[i] << " " << Y[i] << endl ;
        m += 34 ;
        for(int i = 1; i <= 34; i ++) Arm.push_back(1ll << (i - 1)) ;
        for(int i = 1; i <= n; i ++) {
            for(int e = 0; e <= 33; e ++) mx[e] = my[e] = 0 ;
            for(int e = 33; e >= 0 ; e --) {
                if(X[i] <= 0) mx[e] = 1 , X[i] += (1ll<<e) ;
                else if(X[i] > 0) mx[e] = -1 , X[i] -= (1ll<<e) ;
            }
            for(int e = 33; e >= 0 ; e --)
                if(Y[i] <= 0) my[e] = 1 , Y[i] += (1ll<<e) ;
                else if(Y[i] > 0) my[e] = -1 , Y[i] -= (1ll<<e) ;
            for(int e = 0; e <= 33; e ++)
                if(mx[e] > 0 && my[e] > 0) Ans[i].push_back('L') ;
                else if(mx[e] < 0 && my[e] < 0) Ans[i].push_back('R') ;
                else if(mx[e] > 0 && my[e] < 0) Ans[i].push_back('D') ;
                else if(mx[e] < 0 && my[e] > 0) Ans[i].push_back('U') ;
        }
        cout << m << endl ;
        for(int i = 0; i < m; i ++) cout << Arm[i] << " " ;cout << endl ;
        for(int i = 1; i <= n; i ++) {
            for(int j = 0; j < m; j ++) cout << Ans[i][j] ;
            cout << endl ;
        }
        return ;
    }
}

int main() {
    freopen("testdata.in","r",stdin) ;
    n = gi() ;
    bool flag = true ;
    for(int i = 1; i <= n; i ++) {
        X[i] = gi() , Y[i] = gi() ;
        if(!(-10 <= X[i] && X[i] <= 10)) flag = false ;
        if(!(-10 <= Y[i] && Y[i] <= 10)) flag = false ;
    }
    for(int i = 1; i <= n; i ++) dis[i] = abs(X[i]) + abs(Y[i]) ;
    for(int i = 2; i <= n; i ++) if((dis[i]&1) != (dis[1]&1)) {puts("-1") ; return 0 ;}
    cpp600::main() ;
    return 0 ;
}

E-Tr/ee

网址
题目大意:
给定长度为\(n\)的字符串\(S\),
若\(S_i=0\)则表示不能通过割掉一条边形成一个大小为\(i\) 的联通块。
若\(S_i=1\)则表示可以通过割掉一条边形成一个大小为\(i\) 的联通块。
构造符合条件的\(n\)个节点的树,无解输出\(-1\)。
题解:
无解情况:\(S_1=0\)、\(S_n=1\)、\(S_i\neq S_{n-i}\) 。
否则考虑\(S_i=1\) 意味着存在一个大小为\(i\) 的子树,\(S_i=0\)则表示不存在。
考虑从小子树开始构造,设上一次构造出的为大小为\(l\) 的子树。
这次要构造一个大小为\(k\) 的子树,且不能让大小\(\in (l,k)\) 的子树出现。
由于\(S_1 = 1\),即大小为\(1\)的点可以随便用。
所以可以这样:新增一个根,把大小为\(l\) 的子树接在其下,不足的大小\(k-l-1\)全用菊花补全。
代码:

#include<bits/stdc++.h>
#define IL inline
#define _
#define ll long long
using namespace std ;

IL int gi(){
    int data = 0 , m = 1; char ch = 0;
    while(ch!='-' && (ch<'0'||ch>'9')) ch = getchar();
    if(ch == '-'){m = 0 ; ch = getchar() ; }
    while(ch >= '0' && ch <= '9'){data = (data<<1) + (data<<3) + (ch^48) ; ch = getchar(); }
    return (m) ? data : -data ;
}

int n,lst,lst_n,oo,fa[1000005] ; char s[1000000] ;

int main() {
    freopen("testdata.in","r",stdin) ;
    scanf("%s" , s + 1) ;
    n = strlen(s + 1) ;
    if(s[1] == '0' || s[n] == '1') return puts("-1") , 0 ;
    for(int i = 1; i <= n-1; i ++)
        if(s[i] != s[(n-i)]) return puts("-1") , 0 ;
    ++ oo ;
    lst = 1 ;
    int rt = oo ;
    for(int i = 2; i <= n / 2; i ++) {
        if(s[i] == '0') continue ;
        ++ oo ;
        fa[rt] = oo ;
        rt = oo ;
        for(int j = lst + 1; j <= i-1; j++) {
            fa[++oo] = rt ;
        }
        lst = i ;
    }
    //cout << n << ": oo = "<<oo<<endl ;
    fa[rt] = oo + 1 ;
    int root = ++ oo ;
    for(int j = oo + 1; j <= n; j ++) fa[j] = root ;
    for(int i = 1; i <= n; i ++)
        if(i != root) printf("%d %d\n" , i , fa[i]) ;
    return 0 ;
}

F-Distance Sums

网址
题目大意:
给定每个点\(i\)到其它点的距离和\(d_i\)。
构造一棵符合条件的树,无解输出\(-1\),保证\(d\)两两不同。
题解:
考虑\(v\)和它的父亲\(u\)之间的关系:\(d_u = d_v + sz_v - (n-sz_v)\)。
即我们有:\(f_u = d_v - n + 2sz_v\) 。
把\(d\)按照降序排序,显然叶子节点的\(d\)最大,故按照降序枚举。
我们每枚举到一个点,根据上式可以得到其父亲的\(d\)的值,对应连接即可。
若找不到符合条件的\(d\),则无解。
注意这样构造出来的树不一定正确,所以最后再进行一遍树形\(DP\)验证构造正确性。
代码:

#include<bits/stdc++.h>
#define IL inline
#define _ 1000005
#define ll long long
using namespace std ;

IL ll gi(){
    ll data = 0 , m = 1; char ch = 0;
    while(ch!='-' && (ch<'0'||ch>'9')) ch = getchar();
    if(ch == '-'){m = 0 ; ch = getchar() ; }
    while(ch >= '0' && ch <= '9'){data = (data<<1) + (data<<3) + (ch^48) ; ch = getchar(); }
    return (m) ? data : -data ;
}

ll fa[_],sz[_],m,n,d[_],f[_],g[_] ;
struct Item{ll id , dis ; } t[_] ; 

struct _Edge{int to,next ; }Edge[_<<1] ; int head[_],CNT ;
IL void AddEdge(int u , int v) {
    Edge[++CNT] = (_Edge){v , head[u]} ; head[u] = CNT ;
    return ;
}

IL bool cmp1(Item A , Item B){
    return (A.dis ^ B.dis) ? A.dis < B.dis : A.id < B.id ;
}
IL bool cmp2(Item A , Item B){
    return (A.id ^ B.id) ? A.id < B.id : A.dis < B.dis ;
}

void dfs1(int u , int From) {
    sz[u] = 1ll ;
    for(int e = head[u] ; e ; e = Edge[e].next) {
        int v = Edge[e].to ; if(v == From) continue ;
        dfs1(v , u) ;
        f[u] += f[v] + sz[v] ;
        sz[u] += sz[v] ;
    }
    return ;
}
void dfs2(int u , int From) {
    for(int e = head[u] ; e ; e = Edge[e].next) {
        int v = Edge[e].to ; if(v == From) continue ;
        g[v] = f[u] + g[u] - (f[v] + sz[v]) + (n - sz[v]) ;
        dfs2(v , u) ;
    }
    return ;
}

int main() {
    freopen("testdata.in","r",stdin) ;
    n = gi() ;
    for(int i = 1; i <= n; i ++) t[i].id = i , t[i].dis = gi() ;
    sort(t + 1 , t + n + 1 , cmp1) ;
    for(int i = 1; i <= n; i ++) d[i] = t[i].dis ;
    d[n + 1] = 1e18 ;
    for(int i = n; i > 1; i --) {
        int u = t[i].id ;
        sz[u] ++ ;
        ll ds = t[i].dis + 2ll * sz[u] - n ;
        ll ps = lower_bound(d + 1 , d + n + 2 , ds) - d ;
        if(ps >= i || t[ps].dis != ds) return puts("-1") , 0 ;
        fa[u] = t[ps].id ;
        sz[t[ps].id] += sz[u] ;
    }
    sort(t + 1 , t + n + 1 , cmp2) ;
    for(int i = 1; i <= n; i ++) if(fa[i]) AddEdge(fa[i],i) , AddEdge(i,fa[i]) ;
    dfs1(1 , 0) ;
    dfs2(1 , 0) ;
    for(int i = 1; i <= n; i ++) if(f[i]+g[i] != t[i].dis) return puts("-1") , 0 ;
    for(int i = 1; i <= n; i ++) if(fa[i]) cout << fa[i] << " " << i << endl ;
    return 0 ;
}

原文地址:https://www.cnblogs.com/GuessYCB/p/9733436.html

时间: 2024-10-08 16:55:15

AtCoder Regular Contest 103的相关文章

AtCoder Regular Contest 103 题解

C-/\/\/\ #include<algorithm> #include<iostream> #include<cstdlib> #include<iomanip> #include<cstring> #include<complex> #include<vector> #include<cstdio> #include<string> #include<bitset> #includ

AtCoder Regular Contest 103 Problem D Robot Arms (构造)

题目链接  Problem D 给定$n$个坐标,然后让你构造一个长度为$m$的序列, 然后给每个坐标规定一个长度为$m$的序列,ULRD中的一个,意思是走的方向, 每次从原点出发按照这个序列方向,每次走的距离是对应位置的那个值, 最后要走到那个坐标. 直接构造,无解的条件是$x$和$y$的和奇偶性不全相等. 我当时想不出来是因为感觉两个方向不好控制,结果其实可以用二进制统一操作. 如果和是偶数那么加一个往右走一个的单位的操作转化为奇数就行. 然后按照二进制的方法从小到大一个个转换,就像转二进制

AtCoder Beginner Contest 103 D(贪心)

AtCoder Beginner Contest 103 D 题目大意:n个点,除第n个点外第i与第i+1个点有一条边,给定m个a[i],b[i],求最少去掉几条边能使所有a[i],b[i]不相连. 按右端点从小到大排序,如果当前选的去掉的边在区间内,那么符合条件,否则ans++,并贪心地把去掉的边指向右端点,因为前面的区间都满足条件了,所以要去掉的边要尽量向右移使其满足更多的区间. 1 #include <iostream> 2 #include <cstdio> 3 #incl

AtCoder Regular Contest 098

AtCoder Regular Contest 098 C - Attention 题意 给定一个只包含"E","W"字符串,可以花一的花费使他们互相转换.选定一个位置,使位置左边的字符都变成E,右边都变成W所需要的最小花费. 分析 这题纯粹是签到题,做两个前缀和然后直接加就可以了. #include <iostream> #include <cmath> #include <cstring> #include <cstdi

AtCoder Regular Contest 095

AtCoder Regular Contest 095 C - Many Medians 题意: 有A,B两种匹萨和三种购买方案,买一个A,买一个B,买半个A和半个B,花费分别为a,b,c. 求买X个A和Y个B最小花费使多少. 分析: 明显的发现肯定买性价比更高的方案,分情况讨论一下,如果\(a+b<=2*c\),那么明显的先买足c到A,B中较小的一个,然后再比较一下剩下的那个的单价和\(2*c\)的大小. A[ans=] -->|a+b<=2*c| B(A*a+B*b) A -->

AtCoder Regular Contest 094

AtCoder Regular Contest 094 C - Same Integers 题意: 给定\(a,b,c\)三个数,可以进行两个操作:1.把一个数+2:2.把任意两个数+1.求最少需要几次操作将三个数变为相同的数. 分析: 可以发现如果三个数的奇偶性相同直接加就可以了,对于奇偶性不同的,先把奇偶性相同的两个数都+1,然后按照相同的处理就可以了.可以证明没有更好的方案. #include <bits/stdc++.h> using namespace std; int a,b,c,

AtCoder Regular Contest 075 E - Meaningful Mean 树状数组求顺序对, 前缀和

题目链接: http://arc075.contest.atcoder.jp/tasks/arc075_c 题意: 给你一个序列和一个数k,求有多少对l,r,使得a[l]+a[l+1]+...+a[r]的算术平均数大于等于k 1≤N≤2×10^5 1≤K≤10^9 1≤ai≤10^9 思路: 首先对于所有数减去k,这样就不用除(r-l+1), 然后我们发现所求的就是有多少对l,r,使得sum[r]-sum[l-1] >= 0, sum是减去k之后的序列的前缀和 用树状数组对sum求有多少个顺序对

AtCoder Regular Contest 063 E:Integers on a Tree

题目传送门:https://arc063.contest.atcoder.jp/tasks/arc063_c 题目翻译 给你一个树,上面有\(k\)个点有权值,问你是否能把剩下的\(n-k\)个点全部填上权值,使得每条边链接的两个点权值相差\(1\),如果可以做到需要输出任意一组方案. 题解 我们考虑每条边权值为\(1\)或\(-1\),那么相当于黑白染色一样,所有点权值的奇偶性也都是确定的.如果与读入的\(k\)个点中某个点相冲突了就\(GG\).另外每个点的取值范围都可以转化成一段区间\([

AtCoder Regular Contest 062 E - AtCoDeerくんと立方体づくり / Building Cubes with AtCoDeer

题目传送门:https://arc062.contest.atcoder.jp/tasks/arc062_c 题目大意: 给你\(N\)块正方形木板,每块木板四角有四种颜色(可以相同),木板中央有编号,求选出6块不同的板子,围成的本质不同的合法立方体的个数.一个合法立方体,当且仅当木板有编号的一面在外面,且立方体顶点处的三个颜色相同.由于编号的存在,木板可以有4种形态.两个立方体本质相同,当且仅当存在一种空间旋转方式,使得两个立方体一模一样(包括编号方向) 没想到这题巨暴力--当我们确定对面的两