題意
題目要求你將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;
}
總結
這道題我一直做了很久纔想出來,通用的構造形式的推導花了很多功夫,因爲我陷入了一種困境,上面說的三個部分的相鄰元素的確認讓我難以下手寫代碼。直到我畫出了一幅圖,然後根據圖寫代碼才得出解。