Codeforces Round #606 (Div. 2, based on Technocup 2020 Elimination Round 4)
A. Happy Birthday, Polycarp! (CF 1277 A)
题目大意
问到中有多少个数是由一个数字组成的数
解题思路
很显然只有等诸如此类的数,则一共有(位数-)*+首位-+(是否大于以首位数字构成,长度为的数字).
神奇的代码
#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; void Input(void) { string s; cin>>s; int ans=9*(s.size()-1)+s[0]-'0'-1; string ss(s.size(),s[0]); if (ss<=s) ++ans; cout<<ans<<endl; } main(void) { freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); int kase; ios::sync_with_stdio(false); cin>>kase; for (int i = 1; i <= kase; i++) { Input(); } }
B. Make Them Odd (CF 1277 B)
题目大意
给定一个数列,每次操作选择一个偶数,把所有与相同的数都除以,重复此类操作,直到所有数都变为奇数,问最小的操作次数。
解题思路
奇数我们可以忽略,单看偶数,如果某个偶数一直除以得到了一个已有的偶数,则之后的操作可以一并进行,而这类数它们之间就差的次方,于是我们把不断除以得到的奇数是同一个的偶数看做一类,而把它们变成奇数的最小操作次数就是这类数中的最大的偶数。
于是我们把每个偶数都除以,直到变成奇数,对于这每个奇数我们把得到它的最大操作次数记到对答案的贡献里就可以了。
很大,但不大,用个来存,来记录操作次数即可。
神奇的代码
#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); } unordered_map<int,int> an; unordered_set<int> sign; const int N=2e5+8; int n,cnt,ans; void Input(void) { sign.clear(); an.clear(); cnt=0; read(n); for(int u,i=1;i<=n;++i){ read(u); if ((u&1)==0) sign.insert(u); } } void Solve(void) { ans=0; for(auto i:sign){ cnt=0; int x=i; while(!(x&1)){ x>>=1; ++cnt; } an[x]=MAX(an[x],cnt); } for(auto i:an) ans+=i.second; } void Output(void) { write(ans,'\n'); } main(void) { int kase; freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); read(kase); for (int i = 1; i <= kase; i++) { //printf("Case #%d: ", i); Input(); Solve(); Output(); } }
C. As Simple as One and Two (CF 1277 C)
题目大意
给定一个字符串,要求去掉若干个字母,使得该字符串不包含和,求最小的去掉字符的数量。
解题思路
发现和有相同字母,考虑子串,最优的策略就是去掉中间字母,之后剩余单独的和,最优的策略就是去掉中间的字母,因为如果去掉第一位或第三位的话,则这个子串与左边一位或右边一位可能会重新组成或
至于匹配用不用都无所谓……毕竟就的常数
神奇的代码
#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,'\n'); for(int i=1;i<=cnt;++i) printf("%d%c",anspos[i],i==cnt?'\n':' '); if (cnt==0) puts(""); } main(void) { int kase; freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); 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. Let's Play the Words? (CF 1277 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; 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?'\n':' '); else for(int i=1;i<=qwq;++i) cout<<s10[i]<<(i==qwq?'\n':' '); if (qwq==0) cout<<'\n'; } } 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. Two Fairs (CF 1277 E)
题目大意
给定一张个点条边的无向图,有两个特殊城市,求点对数,使得从城市到城市的所有路径中都会经过城市和,其中与均不等于和。
解题思路
我们考虑城市和,很容易想到一种情形就是和把它们之间的点形成了孤岛,这样从的另外一边的城市到的另外一边的城市就必须经过和了。而,就成了连接它们的割点。
那么我们就对进行,记录不经过所能到达的城市,有个,然后再从进行,不经过,如果到达了所到达的城市,那么这个城市就是孤岛上的城市,记有个,否则就是所到达不到,即的另一边的城市,记有个,而a的另一边的城市有个。
那么答案就是.
神奇的代码
#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,'\n'); } int main(void) { //ios::sync_with_stdio(false); freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); int kase; read(kase); for (int i = 1; i <= kase; i++) { //printf("Case #%d: ", i); Input(); Solve(); Output(); } return 0; }
F. Beautiful Rectangle (CF 1277 F)
题目大意
给定个数,将它们放在一个的矩阵格子里,要求放的数最多,且每行和每列中的数都不同。
解题思路
我们先统计每个数出现的次数,并按照出现的次数从大到小排序。
我们尝试去验证是否能构造出的矩阵,其中,对于要填的数,其出现的次数是,有两种情况
- ,这个时候我们只能去个去填充矩阵
- ,这个时候我们可以拿全部去填充矩阵
对于前面的每个数都能填充一列,对于后面的数我们用它们的和除以即可得到填充的列的个数
然后判断列数即是否满足即可
至于构造,这里采用阶梯型构造,对于的数,当构造完底部时就换下一个数,对于的数,用完它再换下一个数。
神奇的代码
#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); } unordered_map<int,int> cnt; vector<pair<int,int>> number; int n,a,b; const int N=4e5+8; int sum[N]; void check(int x){ int qwq=0; for(;qwq<n&&number[qwq].first>=x;++qwq); qwq+=sum[qwq]/x; if (qwq>=x) if (a*b<x*qwq){ a=x; b=qwq; } } void Input(void) { read(n); for(int u,i=1;i<=n;++i) { read(u); cnt[u]++; } for(auto i:cnt) number.push_back(make_pair(i.second,i.first)); } void Solve(void) { sort(number.begin(),number.end(),greater<pair<int,int>>()); int qwq=ceil(sqrt(n)); n=number.size(); sum[n]=0; for(int i=n-1;i>=0;--i) sum[i]=sum[i+1]+number[i].first; //for(int i=0;i<n;++i) cout<<sum[i]<<endl; for(int i=1;i<=qwq;++i) check(i); } void Output(void) { printf("%d\n",a*b); printf("%d %d\n",a,b); int qwq=a*b; int c=0,r=0,qaq=1; int id=0; int tmp[a+1][b+1]; int fen=0; for(;fen<n&&number[fen].first>=a;++fen); while(qwq--){ tmp[r][c]=number[id].second; number[id].first--; c=(c+1)%b; ++r; if (r>=a) {r=0; c=qaq++; if (id<fen) ++id;} if (number[id].first==0) ++id; } for(int i=0;i<a;++i) for(int j=0;j<b;++j) printf("%d%c",tmp[i][j],(j==(b-1))?'\n':' '); } int main(void) { freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); Input(); Solve(); Output(); return 0; }
本文作者:~Lanly~
本文链接:https://www.cnblogs.com/Lanly/p/12041493.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步