【ad-hoc构造】P10033 「Cfz Round 3」Sum of Permutation|普及+
本文涉及知识点
ad-hoc构造
P10033 「Cfz Round 3」Sum of Permutation
题目描述
请注意本题特殊的时间限制。
给定一个 1∼n1\sim n1∼n 的排列 ppp。
你需要构造一个长度为 nnn 的序列 aaa,满足:
- 序列 aaa 中的每个元素均为不大于 nnn 的正整数;
- 不存在有序整数二元组 (l,r)(l,r)(l,r),满足 1≤l≤r≤n1 \le l \le r \le n1≤l≤r≤n 且 ∑i=lrai=∑i=lrpi\sum\limits_{i=l}^r a_i=\sum\limits_{i=l}^r p_ii=l∑rai=i=l∑rpi;
或报告无解。
其中,1∼n1\sim n1∼n 的排列指满足所有不大于 nnn 的正整数恰好出现一次的序列。
输入格式
本题有多组测试数据。
第一行输入一个整数 TTT,表示测试数据组数。
接下来依次输入每组测试数据。对于每组测试数据:
- 第一行输入一个整数 nnn。
- 第二行输入 nnn 个整数,表示给定的排列 ppp。
输出格式
对于每组数据,输出一行:
- 若存在满足条件的序列 aaa,则输出用空格分隔的 nnn 个整数,表示你构造的序列 aaa;
- 若不存在满足条件的序列 aaa,则输出 −1-1−1。
所有满足要求的输出均可通过。
输入输出样例 #1
输入 #1
4
3
3 2 1
2
1 2
5
4 2 1 5 3
7
5 7 3 1 2 4 6
输出 #1
1 3 3
-1
5 3 2 1 1
2 3 5 4 6 3 1
说明/提示
「样例解释 #1」
对于第 111 组数据,{1,3,3}\{1,3,3\}{1,3,3} 和 {1,1,3}\{1,1,3\}{1,1,3} 均为满足条件的序列 aaa。
对于第 222 组数据,可以证明不存在满足条件的序列 aaa。
对于第 333 组数据,除 {5,3,2,1,1}\{5,3,2,1,1 \}{5,3,2,1,1} 外,{3,4,5,3,2}\{3,4,5,3,2 \}{3,4,5,3,2}、{1,4,5,3,4}\{1,4,5,3,4 \}{1,4,5,3,4}、{5,3,3,4,5}\{5,3,3,4,5\}{5,3,3,4,5} 等均为满足条件的序列 aaa。
「数据范围」
设 ∑n\sum n∑n 表示单个测试点中 nnn 的和。
对于所有数据,1≤T≤50001 \le T \le 50001≤T≤5000,2≤n≤1062 \le n \le 10^62≤n≤106,∑n≤106\sum n \le 10^6∑n≤106,保证 ppp 是 1∼n1\sim n1∼n 的排列。
只有你通过本题的所有测试点,你才能获得本题的分数。
本题输入输出量较大,请使用较快的输入输出方式。
构造 ad-hoc
本题 ⟺\iff⟺ p是0∼N−10\sim N-10∼N−1的排列,构造b,使得∀i,j,∑p[i⋯j]≠∑b[i⋯j]\forall i,j ,\sum p[i\cdots j]\neq \sum b[i\cdots j]∀i,j,∑p[i⋯j]=∑b[i⋯j]
能否构造和本题同。如果能构造a[i]=b[i]+1a[i]=b[i]+1a[i]=b[i]+1
方案一:n≥6n \ge 6n≥6
令0==p[j]0==p[j]0==p[j],∀k,j≠k,b[k]=0\forall k,j\neq k,b[k]=0∀k,j=k,b[k]=0
i>j或k<j,∑a[i...k]≠∑p[i...k]i > j 或 k < j,\sum a[i...k] \neq \sum p[i...k]i>j或k<j,∑a[i...k]=∑p[i...k]因为a中任意元素都大于p。
令x=a[j],任意a[i...k]==p[i...k]a[i...k]==p[i...k]a[i...k]==p[i...k]
则说明:p中若干个数和为x,且不包括其它元素。
x=1,说明p中的1和x相邻。如果不相邻 x等于1合法。
x=2,说明p中的2和x相邻。
x=3,说明p中的1和2都和x相邻。x等于3无需判断。
x=4,结合x=1和x=2,说明3和x和1相邻。1、3左邻,2右邻或1、3右邻,2左邻1、3左邻,2右邻或1、3右邻,2左邻1、3左邻,2右邻或1、3右邻,2左邻
x=5,一定合法。
即⋯31x2⋯\cdots 31x2 \cdots⋯31x2⋯,不存在子数组只包括{1,4,x}或{2,3,x}。
n≤2n \le 2n≤2
一定无解
方案二:3≤n≤53 \le n \le 53≤n≤5
同理 p[j]==n−1p[j]==n-1p[j]==n−1将a[j]以外的数,全部设置为n-1,调整a[j]。
3个数时:不能最小值在中间,同时最大值在中间。故不可能两个方案都不成立。
4个数时:最小值左右是第二小第三小,最大值左右是第二大第三大。最小值、最小值左边、最大值、最大右边已经右4个数中,中间的数从那来? 故这种可能不存在。故不可能两个方案都不成立。
5个数时:最小值左边是第三小右边是第四小,最大值右边是第四小,已经超过5个数。故不可能两个方案都不成立。
实现
Check1(j,b,sign) :判断b+1×signb + 1 \times signb+1×sign是不是在j的左右邻。
Check(1的下标,1,1)判断方案一的x等于1;Check(N的下标,N,-1)判断放方案二的x等于1。
Check2(j,b,sign) :判断是否以下情况之一:
a,b+1×signb + 1 \times signb+1×sign 是左邻,b+2×signb + 2 \times signb+2×sign 是右邻。
b,左右邻互换。
Check4(j,b,sign),判断以下情况之一:
a,b+3×signb + 3 \times signb+3×sign b+1×signb + 1 \times signb+1×sign 是左邻,b+2×signb + 2 \times signb+2×sign 是右邻。
b,左右邻互换。
注意:Check1(…,2)可以代替Chck2(…1)
代码
核心代码
#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>
#include<list>
#include<array>#include <bitset>
#include <chrono>
using namespace std::chrono;
using namespace std;template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {in >> pr.first >> pr.second;return in;
}template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t);return in;
}template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);return in;
}template<class T1, class T2, class T3, class T4, class T5 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4, T5>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t) >> get<4>(t) ;return in;
}template<class T1, class T2, class T3, class T4, class T5, class T6 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4, T5, T6>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t) >> get<4>(t) >> get<5>(t) ;return in;
}template<class T1, class T2, class T3, class T4, class T5, class T6, class T7 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4, T5, T6, T7>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t) >> get<4>(t) >> get<5>(t) >> get<6>(t);return in;
}template<class T = int>
vector<T> Read() {int n;cin >> n;vector<T> ret(n);for (int i = 0; i < n; i++) {cin >> ret[i];}return ret;
}
template<class T = int>
vector<T> ReadNotNum() {vector<T> ret;T tmp;while (cin >> tmp) {ret.emplace_back(tmp);if ('\n' == cin.get()) { break; }}return ret;
}template<class T = int>
vector<T> Read(int n) {vector<T> ret(n);for (int i = 0; i < n; i++) {cin >> ret[i];}return ret;
}template<int N = 1'000'000>
class COutBuff
{
public:COutBuff() {m_p = puffer;}template<class T>void write(T x) {int num[28], sp = 0;if (x < 0)*m_p++ = '-', x = -x;if (!x)*m_p++ = 48;while (x)num[++sp] = x % 10, x /= 10;while (sp)*m_p++ = num[sp--] + 48;AuotToFile();}void writestr(const char* sz) {strcpy(m_p, sz);m_p += strlen(sz);AuotToFile();}inline void write(char ch){*m_p++ = ch;AuotToFile();}inline void ToFile() {fwrite(puffer, 1, m_p - puffer, stdout);m_p = puffer;}~COutBuff() {ToFile();}
private:inline void AuotToFile() {if (m_p - puffer > N - 100) {ToFile();}}char puffer[N], * m_p;
};template<int N = 1'000'000>
class CInBuff
{
public:inline CInBuff() {}inline CInBuff<N>& operator>>(char& ch) {FileToBuf();while (('\r' == *S) || ('\n' == *S) || (' ' == *S)) { S++; }//忽略空格和回车ch = *S++;return *this;}inline CInBuff<N>& operator>>(int& val) {FileToBuf();int x(0), f(0);while (!isdigit(*S))f |= (*S++ == '-');while (isdigit(*S))x = (x << 1) + (x << 3) + (*S++ ^ 48);val = f ? -x : x; S++;//忽略空格换行 return *this;}inline CInBuff& operator>>(long long& val) {FileToBuf();long long x(0); int f(0);while (!isdigit(*S))f |= (*S++ == '-');while (isdigit(*S))x = (x << 1) + (x << 3) + (*S++ ^ 48);val = f ? -x : x; S++;//忽略空格换行return *this;}template<class T1, class T2>inline CInBuff& operator>>(pair<T1, T2>& val) {*this >> val.first >> val.second;return *this;}template<class T1, class T2, class T3>inline CInBuff& operator>>(tuple<T1, T2, T3>& val) {*this >> get<0>(val) >> get<1>(val) >> get<2>(val);return *this;}template<class T1, class T2, class T3, class T4>inline CInBuff& operator>>(tuple<T1, T2, T3, T4>& val) {*this >> get<0>(val) >> get<1>(val) >> get<2>(val) >> get<3>(val);return *this;}template<class T = int>inline CInBuff& operator>>(vector<T>& val) {int n;*this >> n;val.resize(n);for (int i = 0; i < n; i++) {*this >> val[i];}return *this;}template<class T = int>vector<T> Read(int n) {vector<T> ret(n);for (int i = 0; i < n; i++) {*this >> ret[i];}return ret;}template<class T = int>vector<T> Read() {vector<T> ret;*this >> ret;return ret;}
private:inline void FileToBuf() {const int canRead = m_iWritePos - (S - buffer);if (canRead >= 100) { return; }if (m_bFinish) { return; }for (int i = 0; i < canRead; i++){buffer[i] = S[i];//memcpy出错 }m_iWritePos = canRead;buffer[m_iWritePos] = 0;S = buffer;int readCnt = fread(buffer + m_iWritePos, 1, N - m_iWritePos, stdin);if (readCnt <= 0) { m_bFinish = true; return; }m_iWritePos += readCnt;buffer[m_iWritePos] = 0;S = buffer;}int m_iWritePos = 0; bool m_bFinish = false;char buffer[N + 10], * S = buffer;
};class Solution {
public:vector<int> Ans(vector<int>& ps) {const int N = ps.size();if (N <= 2) { return { -1 }; }auto Check1 = [&](int inx, int b, int sign) {const bool b1 = inx && (b + sign == ps[inx - 1]);const bool b2 = (inx + 1 < N) && (b + sign == ps[inx + 1]);return b1 || b2;};auto Check4 = [&](int inx, int b, int sign) {const bool b11 = (inx >= 2) && (b + sign == ps[inx - 1]) && (b + 3 * sign == ps[inx - 2]);const bool b12 = (inx + 1 < N) && (b + 2 * sign == ps[inx + 1]);const bool b21 = (inx + 2 < N) && (b + sign == ps[inx + 1]) && (b + 3 * sign == ps[inx + 2]);const bool b22 = (inx >= 1) && (b + 2 * sign == ps[inx - 1]);return (b11 && b12) || (b21 && b22);};const int j1 = find(ps.begin(), ps.end(), 1) - ps.begin();const int jn = find(ps.begin(), ps.end(), N) - ps.begin();vector<int> all1(N, 1), allN(N, N);if (!Check1(j1, 1, 1)) {all1[j1] = 2;return all1;}if (!Check1(jn, N, -1)) {allN[jn] = N - 1;return allN;}if (!Check1(j1, 1, 2)) {all1[j1] = 3;return all1;}if (!Check1(jn, N, -2)) {allN[jn] = N - 2;return allN;}if (!Check4(j1, 1, 1)) {all1[j1] = 5;return all1;}if (!Check4(jn, N, -1)) {allN[jn] = N - 4;return allN;}all1[j1] = 6;return all1;}
};
int main() {
#ifdef _DEBUGfreopen("a.in", "r", stdin);
#endif // DEBUG ios::sync_with_stdio(0); cin.tie(nullptr);//CInBuff<> in; COutBuff<10'000'000> ob;int T;cin >> T;while (T--) { auto ps = Read<int>();
#ifdef _DEBUG //printf("M=%d", M);//Out(A, ",A=");//Out(B, ",B=");//Out(que, ",que=");
#endif // DEBUG Solution slu;auto res = slu.Ans(ps);for (const auto& i : res) {cout << i << " ";}cout << "\n";}return 0;
}
扩展阅读
我想对大家说的话 |
---|
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。 |
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作 |
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注 |
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。 |
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。 |
如果程序是一条龙,那算法就是他的是睛 |
失败+反思=成功 成功+反思=成功 |
视频课程
先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176
测试环境
操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。