2019-12-14 23:21阅读: 419评论: 0推荐: 1

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

A. Happy Birthday, Polycarp! (CF 1277 A)

题目大意

1n中有多少个数是由一个数字组成的数

解题思路

很显然只有11,22,33,44,55,66等诸如此类的数,则一共有(位数-1)*9+首位-1+(n是否大于以首位数字构成,长度为n的数字).

神奇的代码
#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)

题目大意

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

解题思路

奇数我们可以忽略,单看偶数,如果某个偶数一直除以2得到了一个已有的偶数,则之后的操作可以一并进行,而这类数它们之间就差2的次方,于是我们把不断除以2得到的奇数是同一个的偶数看做一类,而把它们变成奇数的最小操作次数就是这类数中的最大的偶数。
于是我们把每个偶数都除以2,直到变成奇数,对于这每个奇数我们把得到它的最大操作次数记到对答案的贡献里就可以了。
ai很大,但n不大,用个unordered_set来存,unordered_map来记录操作次数即可。

神奇的代码
#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)

题目大意

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

解题思路

发现twoone有相同字母o,考虑子串twone,最优的策略就是去掉中间字母o,之后剩余单独的twoone,最优的策略就是去掉中间的字母,因为如果去掉第一位或第三位的话,则这个子串与左边一位或右边一位可能会重新组成twoone
至于匹配用不用KMP都无所谓……毕竟就12的常数

神奇的代码
#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)

题目大意

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

解题思路

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

神奇的代码
#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)

题目大意

给定一张n个点m条边的无向图,有两个特殊城市a,b,求点对数(x,y),使得从城市x到城市y的所有路径中都会经过城市ab,其中xy均不等于ab

解题思路

我们考虑城市ab,很容易想到一种情形就是ab把它们之间的点形成了孤岛,这样从a的另外一边的城市到b的另外一边的城市就必须经过ab了。而ab就成了连接它们的割点。
那么我们就对a进行DFS,记录a不经过b所能到达的城市,有cnta个,然后再从b进行DFS,不经过a,如果到达了a所到达的城市,那么这个城市就是孤岛上的城市,记有d个,否则就是a所到达不到,即b的另一边的城市,记有cntb个,而a的另一边的城市有cntad个。
那么答案就是(cntad)cntb.

神奇的代码
#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)

题目大意

给定n个数,将它们放在一个ab的矩阵格子里,要求放的数最多,且每行和每列中的数都不同。

解题思路

我们先统计每个数出现的次数cnt,并按照出现的次数从大到小排序。
我们尝试去验证是否能构造出ab的矩阵,其中ab,对于要填的数,其出现的次数是cnt,有两种情况

  • cnta,这个时候我们只能去a个去填充矩阵
  • cnt<a,这个时候我们可以拿全部去填充矩阵

对于前面cnta的每个数都能填充一列,对于后面cnt<a的数我们用它们的和cnt除以a即可得到填充的列的个数
然后判断列数即b是否满足ba即可
至于构造,这里采用阶梯型构造,对于cnta的数,当构造完底部时就换下一个数,对于cnt<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);
}
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 中国大陆许可协议进行许可。

posted @   ~Lanly~  阅读(419)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.