题意
题目要求你将a个0,b个1,c个2和d个3排列成一个序列,使得相邻元素的差为1。其中0<=a+b+c+d<=1e5
题意分析
从数据量分析我们能够否定掉暴力的方法。必须观察题设条件总结出规律,然后根据规律设计一种guide,根据这个guide走可以判断是否能够构造出符合要求的序列。经过分析。我将整体情况分解为两种情况:
- abcd四个数中只有相邻的两个数大于0,另外两个数均为零。如:a=2,b=2,c=d=0;这种情况只需要判断|a-b|<=1,满足便能构造出符合要求的序列。不满足则不能构造出符合要求的序列。
- otherwise,其他情况只需要判断 |(b-a) - (c-d)| <= 1,如果满足便能构造出符合要求的序列,不满足则不能。
第一种情况很容易想到,也容易分析,这里直接分析第二种情况。我想出的一种通用构造情况:
(1) 0 1 ... 0 1 2 1 ... 2 1 2 3 ... 2 3 (2)
上面的构造情况将整个结果序列分为3个部分,分别是0 1 重复部分、2 1 重复部分、2 3 重复部分。然后首位括号部分分别是多出的1 和 2可以放到首尾,并且1和2不会同时多出,因为如果同时多出则可以在中间构成一个 2 1的重复。通过这种通用方式构造出来的序列是满足要求的。
参考代码
/*
problem:
author: zxz
time:
memory:
disadvantage:
*/
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <algorithm>
#include <map>
#include <set>
#include <stack>
#include <math.h>
#include <queue>
#include <string>
#include <sstream>
#include <vector>
#include <string.h>
#include <time.h>
#ifndef ONLINE_JUDGE
#include <fstream>
#endif
using namespace std;
const int maxn = 2e5 + 5;
const int INF = 1e9;
void put(char c) {
putchar(c);
putchar(' ');
}
void put(int a, int b, char c, char d) {
puts("YES");
if(a >= b) {
while(b && a) {
printf("%c %c ", c,d);
a--;
b--;
}
if(a>b)
printf("%c", c);
} else {
while(a && b) {
printf("%c %c ",d,c);
a--;
b--;
}
if(b > a)
printf("%c", d);
}
puts("");
}
void solve() {
int a, b,c,d;
scanf("%d %d %d %d", &a, &b,&c,&d);
if(c == 0 && d == 0 && abs(a - b) <= 1) {
put(a,b,'0','1');
return ;
}
if(a == 0 && d == 0 && abs(b - c) <= 1) {
put(b,c,'1','2');
return ;
}
if(a == 0 && b == 0 && abs(c - d) <= 1) {
put(c,d,'2','3');
return ;
}
int ba = b -a;
int cd = c-d;
if(ba>= 0 && cd >= 0 && abs(ba - cd) <= 1) {
puts("YES");
if(ba > cd){
printf("1 ");
}
while(a--){
printf("0 1 ");
}
for(int i = 0; i < min(ba,cd); i++){
printf("2 1 ");
}
while(d--){
printf("2 3 ");
}
if(cd > ba){
printf("2");
}
printf("\n");
} else {
puts("NO");
}
}
int main() {
int t = 1;
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
int mao = clock();
scanf("%d", &t);
#endif
while(t--) {
solve();
}
#ifndef ONLINE_JUDGE
cerr << "Time:" << clock() - mao << "ms" << endl;
ifstream ansf, resf;
ansf.open("ans.txt");
resf.open("out.txt");
string compare1,compare2;
while(!ansf.eof() || !resf.eof()) {
ansf >> compare1;
resf >> compare2;
if(((int)ansf.eof() ^ (int)resf.eof()) || compare1 != compare2) {
cerr << "Result is NO" <<endl;
return 0;
}
}
cerr << "Result is YES" <<endl;
#endif
return 0;
}
总结
这道题我一直做了很久才想出来,通用的构造形式的推导花了很多功夫,因为我陷入了一种困境,上面说的三个部分的相邻元素的确认让我难以下手写代码。直到我画出了一幅图,然后根据图写代码才得出解。