这次div2好难。。打完看介绍才发现不对劲。。
坑了一段时间,发生了好多糟糕的事情 = =、
传送门:Codeforces Round #545 (Div. 2)
A题
题意
给n个数字,这些数字非1即2,要求找出一段连续的长度为len的区间,前len/2为1(或者2),后len/2为2(或者1),输出符合的len的最大值
思路
记录连续相同的数字的长度,比如 2 2 2 1 1 2 2,记录为 3 2 2,然后在两两匹配的最小值中找最大的,就是答案。
代码
注意的是,写的时候cnt[maxn]没有初始化为0,但还是pretest passed了,醒来后发现wa在test35 QAQ这谁顶得住啊.jpg(nmd,wsm!!!)
int main()
{ if(fopen("out1.txt","r")) freopen("out1.txt","r",stdin);
int T,n,m,k,i,sum,j,t,tmp,flag = 0;
scanf("%d",&n);
int a[maxn],cnt[maxn]={0};
sum = 0;
/*
for(i=0;i<n;i++){
scanf("%d",&a[i]);
if(i==0) { cnt[a[i]]++; continue; }
if(a[i]!=a[i-1]){
if(flag==0){
flag = 1;
cnt[a[i]]++;
}else if(flag==1){
cnt[a[i]]++;
sum = max(sum,min(cnt[1],cnt[2]));
cnt[1] = cnt[2] = flag = 0;
}
}else{
cnt[a[i]]++;
}
}
sum = max(sum,min(cnt[1],cnt[2]));
*/
t = 0;
cnt[t] = 1;
for(i=0;i<n;i++){
scanf("%d",&a[i]);
if(i==0) continue;
if(a[i]==a[i-1]){
cnt[t]++;
}else cnt[(++t)]++;
}
for(i=1;i<=t;i++){
sum = max(sum,min(cnt[i-1],cnt[i]));
}
printf("%d\n",sum*2);
return 0;
}
B题
题意
第一行一个n,表示有n个演员,有些演员可以扮演clown,有些可以扮演acrobat。第二行有n个0或1,表示第i个演员可不可以扮演clown,第三行有n个0或1,表示第i个演员可不可以扮演acrobat。要选择 n/2 个演员出演第一场,并输出所选的这 n/2 个演员的编号。
要求第一场出演的演员,能扮演clown的,和第二场出演的演员,能扮演acrobat的,数量一样。(只能扮演clown的演员,可以放在第二场出演,则演不了clown又演不了acrobat)
假思路
00表示都不能演,10表示只能演clown,01表示只能演acrobat,11表示都能演。
统计00,10,01,11的个数,一个 10 和 一个01 搭配,如果 10 比 01 多,则多出来的和11匹配,少的话,01 多出来的和11匹配,如果数量一样的话,如果11是奇数的话,就输出-1,否则分一半匹配。。。
然后数量一样的那里,第一个例子就验证是错的了。。。
官方思路
设 00 ,01 ,10 ,11 的总数分别是
n
a
n_a
na,
n
b
n_b
nb,
n
c
n_c
nc,
n
d
n_d
nd。设第一轮中, 00 ,01 ,10 ,11 这四种演员的数量分别是 a , b , c , d ,所以,第二轮中, 00 ,01 ,10 ,11 这四种演员的数量分别是
n
a
n_a
na - a,
n
b
n_b
nb - b,
n
c
n_c
nc - c,
n
d
n_d
nd - d。根据题目有:a + b + c + d =
n
2
\dfrac{n}{2}
2n 。而第一轮选择的演员能扮演clown的有 c + d 个,第二轮中选择的演员能扮演acrobat的有(
n
b
n_b
nb - b )+ (
n
d
n_d
nd - d )个,根据题目要求:c + d = (
n
b
n_b
nb - b )+ (
n
d
n_d
nd - d ),整理得 c + b + 2d =
n
b
n_b
nb +
n
d
n_d
nd。
现在知道了两个式子,和四个未知数,可以用暴力来解决:确定a,b,c,d中 其中两个,来求出剩下两个,在看看这四个是否符合数据范围:0 ≤    \leq\; ≤ x ≤    \leq\; ≤ nx
思路对比
emmm 设出四个未知数之后,不应该去考虑搭配的问题,因为有很多种搭配 = = 想到后来都爆炸了,还想着10和01的数量不能超过
n
2
\dfrac{n}{2}
2n,然后之后怎么怎么样。。。。没有想到去列出式子,然后直接暴力。第一个式子好列,第二个式子需要想想,但也不难知道。复杂度感觉是
n
2
n^2
n2,不过5000的
n
2
n^2
n2会超时啊。。。看了题解实际上是
5000
2
2
\frac{5000}{2}^2
250002,吧。
代码
int T,n,m,k,i,sum,j,td,ta,tmp;
int na,nb,nc,nd,a,b,c,d;
char sc[5005],sa[5005];
int main()
{ if(fopen("in.txt","r")) freopen("in.txt","r",stdin);
scanf("%d%s%s",&n,sc,sa);
for(i=0;i<n;i++){
if(sc[i]=='0'&&sa[i]=='0') na++;
else if(sc[i]=='0'&&sa[i]=='1') nb++;
else if(sc[i]=='1'&&sa[i]=='0') nc++;
else if(sc[i]=='1'&&sa[i]=='1') nd++;
}
int flag = 0;
for(i=0;i<=nb;i++){
for(j=0;j<=nc;j++){
td = nb+nd-i-j;
if(td<0||td&1) continue;
td /= 2;
if(td>nd) continue;
ta = n/2 - i - j - td;
if(0<=ta&&ta<=na){
flag = 1;
break;
}
}
if(flag) break;
}
if(!flag) printf("-1\n");
else{
a = ta; b = i; c = j; d = td;
// cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl;
for(i=0;i<n;i++){
if(sc[i]=='0'&&sa[i]=='0'&&a>0){
if(a--) printf("%d%c",i+1,i==n-1?'\n':' ');
}else if(sc[i]=='0'&&sa[i]=='1'&&b>0){
if(b--) printf("%d%c",i+1,i==n-1?'\n':' ');
}else if(sc[i]=='1'&&sa[i]=='0'&&c>0){
if(c--) printf("%d%c",i+1,i==n-1?'\n':' ');
}else if(sc[i]=='1'&&sa[i]=='1'&&d>0){
if(d--) printf("%d%c",i+1,i==n-1?'\n':' ');
}
}
}
return 0;
}
C题
题意
给大小为
n
∗
m
n*m
n∗m的矩阵,表示
n
∗
m
n*m
n∗m 个高楼的高度。对于第 i 行第 j 列组成的十字,要求给楼的高度编号,整个图从1开始编号(某行/列可以缺一些数字),更高的楼编号更大。第 i 行和第 j 列的楼的高度不互相影响,只用参照本行/列的高度进行编号。最后输出这个十字中的最大编号。
思路
首先离散化一下,用的map离散。然后得出一个数在那行和那列中排第几。取该数在它的行与列中排名较大的。如果是行中排列比较大的,那么就要在行的基础上,加上在列中排名的“偏移量”,比如行中排x名,列中排y名,就要计算出该数在列中头顶还排有多少个比它大的数字,计算出的差就是“偏移量”,x+偏移量 才可能对答案做贡献,最后把它和该行的最大编号中取最大值。
对于行和列中取了排名较小的 的话,例子:
2 2
1 2
3 4
对于3,3在行中编号为1,列中编号为2,如果取排名较小的话,那就是先看横行再看纵行,变成:
0
1 2
编号0这里不好计算,如果取编号大的,会比较好算:
1
2 3
好像讲得有点啰嗦了 = =
代码
int a[1005][1005],row[1005][1005],col[1005][1005];
int maxrow[1005],maxcol[1005];
int main()
{ if(fopen("in.txt","r")) freopen("in.txt","r",stdin);
int T,n,m,k,i,sum,j,t,tmp;
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
for(j=0;j<m;j++) scanf("%d",&a[i][j]);
for(i=0;i<n;i++){
map<int,int > mp; t = 0;
for(j=0;j<m;j++) mp[a[i][j]];
for(auto &it:mp) it.second = ++t;
for(j=0;j<m;j++) row[i][j] = mp[a[i][j]];
maxrow[i] = t;
// for(j=0;j<m;j++) printf("%d - ",row[i][j]);
}
for(i=0;i<m;i++){
map<int,int >mp; t = 0;
for(j=0;j<n;j++) mp[a[j][i]];
for(auto &it:mp) it.second = ++t;
for(j=0;j<n;j++) col[j][i] = mp[a[j][i]];
maxcol[i] = t;
// for(j=0;j<n;j++) printf("%d : ",col[j][i]);
// cout<<endl;
}
//cout<<maxrow[3]<<endl;
for(i=0;i<n;i++){
for(j=0;j<m;j++){
// cout<<col[i][j]<<" - "<<row[i][j]<<" "<<maxrow[i]<<" "<<maxcol[i]<<endl;
if(col[i][j]>row[i][j]){
t = max(col[i][j] + maxrow[i] - row[i][j],maxcol[j]);
}else{
t = max(row[i][j] + maxcol[j] - col[i][j],maxrow[i]);
}
printf("%d%c",t,j==m-1?'\n':' ');
//printf("%d\n",t);
}
}
return 0;
}
/*
3 5
12 7 15 4 9
3 1 5 12 15
19 17 25 10 21
*/