容易推出当移动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;
}
这几天做了点动态规划的题目,第一次做还是有点手足无措,现在对最优子结构,无后效性,状态的理解深了不少,难点在于状态转移方程,要观察元素的来历而不是去向,想清楚这个状态是由哪几个状态递推而来,分别有什么差别,以及如何判断状态,想清楚之后就能将首个元素写入,再类似数学归纳法一样一步一步递推出正确答案。