容易推出当移动i与j时等价于j-i-1个左右交换,且每次交换逆序数的奇偶改变(无相同元素),假设有一个状态c,且a与b必须以等量的左右交换转移为c,则必须数量相同,元素相同(使用异或解决),逆序数奇偶性相同(归并排序解决)代码如下
<bits/stdc++.h>
#include<algorithm>
#define ll long long
#define max_int 2147483647
#define max_ll 9223372036854775807
using namespace std;
ll merge(ll left, ll right, vector<ll>& arr) { if (left >= right) return 0; ll mid = left + (right - left) / 2; ll inv_count = merge(left, mid, arr) + merge(mid + 1, right, arr); vector<ll> temp; int i = left, j = mid + 1, k = 0; while (i <= mid && j <= right) { if (arr[i] <= arr[j]) { temp.push_back(arr[i++]); } else { temp.push_back(arr[j++]); inv_count += (mid - i + 1); // 累加跨越中点的逆序数 } } while (i <= mid) { temp.push_back(arr[i++]); } while (j <= right) { temp.push_back(arr[j++]); } for (k = 0; k < temp.size(); k++) { arr[left + k] = temp[k]; } return inv_count;
}
int main(){ios::sync_with_stdio(false);cin.tie(0);ll all;cin>>all;while(all--){ll n;cin>>n;vector<ll>q1(n+10);vector<ll>q2(n+10);ll xorsum=0;for(ll i=0;i<n;++i) cin>>q1[i],xorsum^=q1[i];for(ll i=0;i<n;++i) cin>>q2[i],xorsum^=q2[i];if(xorsum!=0){cout<<"NO"<<endl;continue;}//cout<<merge(0,n-1,q1)<<" "<<merge(0,n-1,q2)<<endl;if((merge(0,n-1,q1)%2)^(merge(0,n-1,q2)%2)) cout<<"NO"<<endl;else cout<<"YES"<<endl;}return 0;
先用前缀和预处理,再遍历3的阶乘,映射关系要看准
<bits/stdc++.h>
#include<algorithm>
#define ll long long
#define max_int 2147483647
#define max_ll 9223372036854775807
using namespace std;
vector<vector<ll>>q(5,vector<ll>(200005));
int longth;
bool check(int i,int j,int k){int end=0,front,z=1;int an[4]={0,i,j,k};vector<vector<ll>>target(4,vector<ll>(2));target[an[i]][0]=1;ll tot=(q[1][longth]+2)/3;while(z<4){front=end+1;if(front>longth) return false;target[an[z]][0]=front;while(q[an[z]][front]-q[an[z]][end]<tot&&front<=longth) front++;if(front>longth){//cout<<"-1"<<endl;return false;}target[an[z]][1]=front;end=front;z++;}cout<<target[1][0]<<' '<<target[1][1]<<' '<<target[2][0]<<' '<<target[2][1]<<' '<<target[3][0]<<' '<<target[3][1]<<' '<<endl;return true;
}
int main(){ios::sync_with_stdio(false);cin.tie(0);int all;cin>>all;while(all--){cin>>longth;for(int i=1;i<=3;++i){for(int p=1;p<=longth;++p){cin>>q[i][p];q[i][p]+=q[i][p-1];}}if(check(1,2,3)) continue;else if(check(1,3,2)) continue;else if(check(2,1,3)) continue;else if(check(2,3,1)) continue;else if(check(3,1,2)) continue;else if(check(3,2,1)) continue;else cout<<"-1"<<endl;}return 0;
}
这几天做了点动态规划的题目,第一次做还是有点手足无措,现在对最优子结构,无后效性,状态的理解深了不少,难点在于状态转移方程,要观察元素的来历而不是去向,想清楚这个状态是由哪几个状态递推而来,分别有什么差别,以及如何判断状态,想清楚之后就能将首个元素写入,再类似数学归纳法一样一步一步递推出正确答案。