【题解】洛谷P3531、P1966:LIT-Letters 、火柴排队

P3531 [POI2012] LIT-Letters

写了个假做法有点伤心,本以为是两个都求逆序对然后答案相减,但是这样在部分数据上确实合法,但是实际上毫无章法没有逻辑。

正解考虑贪心,我们一个数字肯定要找最前面,第二次出现就去最前面第二次出现的位置,因为如果第一个A放在了后面,那么就有可能产生更对逆序对(因为你把大的数放在了前面)。

我们对每个字母重新编号,\(A\)ABC 编号为 123\(B\)CBA 编号为 321

接下来就可以正常求逆序对了。

其实思想就是多个重复的我们进行去重,让他们有对应的编号,像原来为 \(A\)010\(B\)100,完全没法去逆序对,不知道的还以为是区间差逆序对呢,但是我们重编号就为 123,213 这就很明确了,我们都尽量向前靠,每个数该去哪就去哪。

#include<bits/stdc++.h>
#define int long long
#define ls p<<1
#define rs p<<1|1 
#define re register 
const int N=1e6+10;
const int mod=998244353;
using namespace std;

int n;

int a[N],b[N];
 

int t[N];

int lb(int x){
	return x&-x;
}

void add(int x,int k){
	while(x<=n){
		t[x]+=k;
		x+=lb(x);
	}
}

int query(int x){
	int sum=0;
	while(x){
		sum+=t[x];
		x-=lb(x);
	}
	return sum;
}

int vis[30][N];
int tt[100]; 

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 
	
	cin>>n;
	
	for(int i=1;i<=n;i++){
		char c;
		cin>>c;
		a[i]=c-'A'+2;
	}
	for(int i=1;i<=n;i++){
		char c;
		cin>>c;
		b[i]=c-'A'+2;
	}
	
	for(int i=1;i<=n;i++){
		vis[a[i]][++vis[a[i]][0]]=i;
	} 
	for(int i=1;i<=n;i++){
		b[i]=vis[b[i]][++tt[b[i]]];
	} 
	int ans=0;
	for(int i=n;i>=1;i--){
		ans+=query(b[i]-1);
		add(b[i],1);
	}
	cout<<ans;
	
	return 0;
}

P1966 [NOIP2013 提高组] 火柴排队

这是上面那题的略微复杂版,可以想到上面最大与下面最大这样造成的代价最小,欸!是大小关系不是具体数值,我们进行离散化去重可以分别得到 1 3 4 2 与 1 4 2 3,可以发现到这就是对应数字到对应位置,直接套上一题的模板即可,注意:题目已经说了一盒火柴互不相同所以不用去重,但就这样吧。

#include<bits/stdc++.h>
//#define int long long
#define ll long long
#define ls p<<1
#define rs p<<1|1 
#define re register 
const int N=1e5+10;
const int mod=1e8-3;
using namespace std;

int n;

int a[N],b[N];

ll t[N];

inline int lb(int x){
	return x&-x;
}

int mx=0;

inline void add(int x,int k){
	while(x<=mx){
		t[x]+=k;
		t[x]%=mod;
		x+=lb(x);
	}
}

inline int query(int x){
	ll sum=0;
	while(x){
		sum+=t[x];
		sum%=mod;
		x-=lb(x);
	}
	return sum;
}

int vis[N][100];
int tt[N]; 

int f1[N],o1=0;
int f2[N],o2=0;
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 
	
	cin>>n;
	
	for(re int i=1;i<=n;i++){
		cin>>a[i];
		f1[++o1]=a[i];
	}
	for(re int i=1;i<=n;i++){
		cin>>b[i];
		f2[++o2]=b[i];
	}
	
	sort(f1+1,f1+o1+1);
	sort(f2+1,f2+o2+1);
	
	int tot1=unique(f1+1,f1+o1+1)-f1-1;
	int tot2=unique(f2+1,f2+o2+1)-f2-1;
	
	for(re int i=1;i<=n;i++){
		a[i]=lower_bound(f1+1,f1+1+tot1,a[i])-f1;
		b[i]=lower_bound(f2+1,f2+1+tot2,b[i])-f2;
	}
	
	if(tot1<tot2){
		swap(a,b);
	}
	
	mx=max(tot1,tot2);
	
//	cout<<tot1<<" "<<tot2;
	
	for(re int i=1;i<=n;i++){
		vis[a[i]][++vis[a[i]][0]]=i;
	} 
	for(re int i=1;i<=n;i++){
		b[i]=vis[b[i]][++tt[b[i]]];
	} 
	ll ans=0;
	for(re int i=n;i>=1;i--){
		ans+=query(b[i]-1);
		ans%=mod;
		add(b[i],1);
	}
	cout<<ans;
	return 0;
}
posted @ 2024-11-21 09:06  sad_lin  阅读(0)  评论(0编辑  收藏  举报