Codeforces Round #606 (Div. 2, based on Technocup 2020 Elimination Round 4)

Posted hgangang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #606 (Div. 2, based on Technocup 2020 Elimination Round 4)相关的知识,希望对你有一定的参考价值。

 

B

给定一个数列,每次操作选择一个偶数cc,把所有与cc相同的数都除以22,重复此类操作,直到所有数都变为奇数,问最小的操作次数。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
int a[maxn];
ll n;
unordered_map<int,int>vis;
bool cmp(int a,int b){
    return a>b;
}
int main()
{
	ll  t;
	cin>>t;
	while(t--){
        cin>>n;
        vis.clear();
        ll ans=0;
        for(int i=1;i<=n;i++)cin>>a[i];
        sort(a+1,a+1+n,cmp);
        for(int i=1;i<=n;i++){
            if(vis[a[i]]==0&&(a[i]&1)==0){
                vis[a[i]]=1;
                while(a[i]){
                    ans++;a[i]/=2;vis[a[i]]=1;
                    if(a[i]&1) break;
                }
            }
        }
        cout<<ans<<endl;
	}
}

  C

给定一个字符串,要求去掉若干个字母,使得该字符串不包含"one""one"和"two""two",求最小的去掉字符的数量。

有以下三个情况:

(1):one,ooone这种,那直接取消n或者e,而不是o

(2):two,twooo这种,那直接取消t或者w,而不是o

(3)twone直接取消o;

用kmp先匹配twone,因为先匹配one和two的话twone这个还得再搞一次。

#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
 
template <typename T>
void read(T &x) {
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c)) c = getchar();
    if (c == 45) s = 1, c = getchar();
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s) x = -x;
}
 
template <typename T>
void write(T x, char c = ‘ ‘) {
    int b[40], l = 0;
    if (x < 0) putchar(45), x = -x;
    while (x > 0) b[l++] = x % 10, x /= 10;
    if (!l) putchar(48);
    while (l) putchar(b[--l] | 48);
    putchar(c);
}
 
char one[4]={"one"};
 
char two[4]={"two"};
 
char twone[6]={"twone"};
 
int nxtone[4],nxttwo[4],nxttwone[6];
 
const int N=2e5+8;
 
char s[N];
 
int len,cnt;
 
int anspos[N];
 
void makenext(char qaq[],int nxt[],int n){
    nxt[0]=0;
    int k=0;
    for (int i=1;i<n;i++){
        while ((k>0)&&(qaq[k]!=qaq[i])) k=nxt[k-1];
        if (qaq[k]==qaq[i]) k++;
        nxt[i]=k;
    }
}
 
void kmp(char qaq[],int nxt[],char qwq[],int n){
    int q=0;
    for (int i=0;i<len;i++){
        if (qwq[i]==‘@‘) continue;
        while ((qwq[i]!=qaq[q])&&(q>0)) q=nxt[q-1];
        if (qwq[i]==qaq[q]) q++;
        if (q==n) {
            if (n==5) {qwq[i-2]=‘@‘; anspos[++cnt]=i-1;}
            else {qwq[i-1]=‘@‘; anspos[++cnt]=i;}
        }
    }
}
 
void Input(void) {
    cnt=0;
    scanf("%s",s);
    len=strlen(s);
}
 
void Solve(void) {
    kmp(twone,nxttwone,s,5);
    kmp(two,nxttwo,s,3);
    kmp(one,nxtone,s,3);
}
 
void Output(void) {
    write(cnt,‘
‘);
    for(int i=1;i<=cnt;++i) printf("%d%c",anspos[i],i==cnt?‘
‘:‘ ‘);
    if (cnt==0) puts("");
}
 
main(void) {
    int kase;
    read(kase);
    makenext(one,nxtone,3);
    makenext(two,nxttwo,3);
    makenext(twone,nxttwone,5);
    for (int i = 1; i <= kase; i++) {
        //printf("Case #%d: ", i);
        Input();
        Solve();
        Output();
    }
}

  D

题目大意

给定若干个互不相同的0101子串,现翻转一些子串,使得这些子串可以排成一行,第一个子串任意,然后前一个子串的末数字和后一个子串的首数字一样,且不能有相同的子串。求最小的翻转次数,且输出任一种对应的方案。无解则输出1−1

解题思路

考虑到只涉及子串的首位和末位,我们按照首位和末位的数字将这些子串分为44类,即00,01,10,1100,01,10,11串。
无解的情况就是有0000串和1111串但无1010和0101串。
由植树原理知只要1010串和0101串的数量差值小于等于11即可。
因为0101串翻转就是1010串,那么最小的操作次数就是1010和0101串的数量差的一半下取整。但这里可能会出现翻转后的子串与已有的子串相同。
因为0000串和1111串无需翻转,我们就不用考虑它们。
注意到如果一个0101串翻转后与已有的子串相同,这个已有的子串一定是1010串,且可以和翻转的0101串进行匹配,我们就可以不考虑这对子串了。

#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;

const int N=2e5+8;

int num[4],s01[N],s10[N];

int n,l,c0,c1;

string s,ss;

unordered_map<string,pair<int,bool>> qwq;

void Input(void) {
    qwq.clear();
    num[0]=num[1]=num[2]=num[3]=0;
    c0=c1=0;
    cin>>n;
    for(int i=1;i<=n;++i){
        cin>>s;
        if (s[0]==s[s.size()-1]) {qwq[s]=make_pair(i,1);continue;}
        ss=s;
        reverse(s.begin(),s.end());
        if (qwq[s].second==1) {qwq[s].second=0;++num[2];++num[3];continue;}
        qwq[ss]=make_pair(i,1);
    }
}

void Solve(void) {
    for(auto v:qwq){
        if (v.second.second==1){
        const char *ss=v.first.c_str();
            l=strlen(ss);
            if (l==1) ++num[ss[0]-‘0‘];
            else{
                if (ss[0]==‘0‘&&ss[l-1]==‘0‘) ++num[0];
                else if (ss[0]==‘0‘&&ss[l-1]==‘1‘) ++num[2],s01[++c0]=v.second.first;
                else if (ss[0]==‘1‘&&ss[l-1]==‘0‘) ++num[3],s10[++c1]=v.second.first;
                else ++num[1];
            }
        }
    }
    if (num[2]==0&&num[3]==0&&num[0]!=0&&num[1]!=0) cout<<"-1"<<endl;
    else {
        int qwq=ABS(num[2]-num[3]);
        qwq/=2;
        cout<<qwq<<endl;
        if (num[2]>num[3]) for(int i=1;i<=qwq;++i) cout<<s01[i]<<(i==qwq?‘
‘:‘ ‘);
        else for(int i=1;i<=qwq;++i) cout<<s10[i]<<(i==qwq?‘
‘:‘ ‘);
        if (qwq==0) cout<<‘
‘;
    }
}

void Output(void) {}

main(void) {
    ios::sync_with_stdio(false);
    int kase;
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    cin>>kase;
    for (int i = 1; i <= kase; i++) {
        //printf("Case #%d: ", i);
        Input();
        Solve();
        Output();
    }
}

  E

 

题目大意

给定一张nn个点mm条边的无向图,有两个特殊城市a,ba,b,求点对数(x,y)(x,y),使得从城市xx到城市yy的所有路径中都会经过城市aa和bb,其中xx与yy均不等于aa和bb。

解题思路

我们考虑城市aa和bb,很容易想到一种情形就是aa和bb把它们之间的点形成了孤岛,这样从aa的另外一边的城市到bb的另外一边的城市就必须经过aa和bb了。而aa,bb就成了连接它们的割点。
那么我们就对aa进行DFSDFS,记录aa不经过bb所能到达的城市,有cntacnta个,然后再从bb进行DFSDFS,不经过aa,如果到达了aa所到达的城市,那么这个城市就是孤岛上的城市,记有dd个,否则就是aa所到达不到,即bb的另一边的城市,记有cntbcntb个,而a的另一边的城市有cntadcnta−d个。

#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;

template <typename T>
void read(T &x) {
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c)) c = getchar();
    if (c == 45) s = 1, c = getchar();
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s) x = -x;
}

template <typename T>
void write(T x, char c = ‘ ‘) {
    int b[40], l = 0;
    if (x < 0) putchar(45), x = -x;
    while (x > 0) b[l++] = x % 10, x /= 10;
    if (!l) putchar(48);
    while (l) putchar(b[--l] | 48);
    putchar(c);
}

const int N=2e5+8;

vector<int> edge[N];

int n,m,a,b;

int sign[N];

long long cnta,cntb;

void Input(void) {
    read(n);
    read(m);
    read(a);
    read(b);
    for(int i=1;i<=n;++i) edge[i].clear();
    for(int u,v,i=1;i<=m;++i){
        read(u);
        read(v);
        edge[u].push_back(v);
        edge[v].push_back(u);
    }
}
void DFSa(int x){
    for(auto i:edge[x]){
        if (i==b) continue;
        if (sign[i]==0){
            sign[i]=1;
            ++cnta;
            DFSa(i);
        }
    }
}
void DFSb(int x){
    for(auto i:edge[x]){
        if (i==a) continue;
        if (sign[i]!=2){
            if (sign[i]==1) --cnta;
            else ++cntb;
            sign[i]=2;
            DFSb(i);
//            continue;
        }

    }
}
void Solve(void) {
    for(int i=1;i<=n;++i) sign[i]=0;
    cnta=cntb=0;
    sign[a]=1;
    DFSa(a);
    sign[b]=2;
    DFSb(b);
}
void Output(void) {
    write(cntb*cnta,‘
‘);
}
int main(void) {
    //ios::sync_with_stdio(false);
    int kase; read(kase);
    for (int i = 1; i <= kase; i++) {
        //printf("Case #%d: ", i);
        Input();
        Solve();
        Output();
    }
    return 0;
}

  


那么答案就是(cntad)cntb(cnta−d)∗cntb.

以上是关于Codeforces Round #606 (Div. 2, based on Technocup 2020 Elimination Round 4)的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #606 (Div. 2, based on Technocup 2020 Elimination Round 4)

Codeforces Round #606 (Div. 2, based on Technocup 2020 Elimination Round 4)

cf比赛记录Codeforces Round #606 (Div. 2, based on Technocup 2020 Elimination Round 4)

Codeforces Round #606 (Div. 2) E - Two Fairs(DFS,反向思维)

Codeforces Round #606 (Div. 2) D. Let's Play the Words?(贪心+map)

Codeforces Round #436 E. Fire(背包dp+输出路径)