问题描述:
AC代码:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<map> 5 #include<set> 6 #include<vector> 7 #include<algorithm> 8 #include<cmath> 9 #include<fstream> 10 #include<iomanip> 11 #include<queue> 12 #include<unordered_set> 13 using namespace std; 14 typedef long long ll; 15 typedef unsigned long long ull; 16 const ll maxn = 300 + 5; 17 int target; 18 19 int num = 1; 20 21 int a[maxn], b[maxn]; 22 bool f[maxn][maxn][maxn]; 23 24 void dfs(int n, int x, int y){ 25 if(f[n][x][y])return; 26 f[n][x][y] = true; 27 if(n == target - 1){ 28 for(int i = 0; i <= 2; i++){ 29 if((3 * a[n] - b[n - 1] + i) / 2 == a[n + 1]){//原等式 应为 2 * a[n + 1] (+1) = 3 * a[n] - b[n - 1](+1) (+2) 其中括号为可选项,代码里左边等式的 +1 消失了是因为有 /2 的存在。 30 b[n + 1] = 3 * a[n] - b[n - 1] - b[n] + i; 31 for(int i = 1; i <= target; i++){ 32 cout << b[i] << " "; 33 } 34 exit(0); 35 } 36 } 37 } 38 for(int i = 0; i < 3; i++){ 39 b[n + 1] = 3 * a[n] - b[n] - b[n - 1] + i; 40 if(b[n + 1] >= 1)dfs(n + 1, y, b[n + 1]); 41 } 42 return; 43 } 44 45 46 int main(){ 47 // ios::sync_with_stdio(false); 48 // ifstream cin("data.txt"); 49 // freopen("data.txt", "r", stdin); 50 memset(f, false, sizeof(f)); 51 int n; 52 cin >> n; 53 target = n; 54 for(int i = 1; i <= n; i++){ 55 cin >> a[i]; 56 } 57 for(int i = 1; i <= 2 * a[1]; i++){ 58 b[1] = i; 59 if(i != 2 * a[1]){ 60 b[2] = 2 * a[1] - i; 61 dfs(2, b[1], b[2]); 62 } 63 b[2] = 2 * a[i] - i + 1; 64 dfs(2, b[1], b[2]); 65 } 66 return 0; 67 }
我想说的:
很菜很菜的我在绝望搜题解之前是懵逼的,搜了几篇题解都是 差分约束 的解法,然而,看到了这篇博客 https://blog.csdn.net/imotolove/article/details/82777819 ,让我眼前一亮!对啊,可以暴力的啊!
我们的思路就是:
假设 b[] 为所求 a[] 为已知。
我们把不等式写出来可以得到递推式:3 * a[n] <= b[n + 1] + b[n - 1] + b[n] <= 3 * a[n] + 2
即, 我们知道 b[n - 1]、 b[n] 时 只需枚举 0, 1, 2即可得到 b[n + 1]
对于起始和结束的特殊情况, 改写上式。
对于起始的 b[1] 和 b[2], 我们知道 2 * a[1] <= b[1] + b[2] <= 2 * a[1] + 1
即我们只需从 1 到 2 * a[1]枚举 b[1] 即可确定 两个初值
对于最后的值 b[target] , 我们需保证 同时 满足 两个式子 才能 确定最后一个值
对于 dfs的有效性:
我们按递推式去推 b[],若可以推出来,则一定符合题意(因为递推式是满足题意的),
否则,中间某值出现小于 1 的情况 或者 最后的值不符合两个不等式,都会记忆下然后退出来。
每次碰到之前记忆过得情况时,直接退出, 因为之前通过这条路走不通没必要浪费时间。
对于字典序的解释:
我们是依次从小到大从前往后搜的,所以第一次满足题意的解 也 一定满足了字典序最小的要求。
最后再鸣谢一下这位CSDN博主给我的启发: