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



















