1 条题解

  • 0
    @ 2026-4-29 1:54:17

    对于一种字母,记其出现次数为 numinum_i\\ 显然前面出现的 numi2\frac{num_i}{2} 的字母都给它移到前 nn 个字符中,后面出现的 numi2\frac{num_i}{2} 扔到后面 nn 个字符中更优。记录 head1head_1 表示前面已经填了多少个字符,如果当前位置要移到前 nn 个位置中,其耗费的代价为 ihead1i-head_1,扔到后面 nn 个位置的话不用考虑代价,因为将前 nn 个填满后剩下的自然就到了后面去。
    接下来考虑怎么计算使前后两部分相等的代价,记 q1q_1 为扔到前面的 nn 个字符的顺序,q2q_2 为后面 nn 个的顺序,那么这道题就转化为每次可以交换相邻的两个元素,问最少多少次可以使 q1q_1 序列变成 q2q_2 序列,也就是 P1966,但是需要注意的时相同的字符显然要前面指向前面的,后面指向后面的更优,因为可以减少相对顺序的逆序对数量。\\ 细节不多,主要是后面处理相同字符比较麻烦。

    //write by szh
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    ll read() {
    	ll x=0,f=1;
    	char ch=getchar();
    	while (ch<'0'||ch>'9') {
    		if (ch=='-') f=-1;
    		ch=getchar();
    	}
    	while (ch>='0'&&ch<='9') {
    		x=x*10+ch-48;
    		ch=getchar();
    	}
    	return x*f;
    }
    const ll N=2e5+10;
    ll n;
    char a[2*N];
    ll q1[N],q2[N];
    ll head1,head2,ans;
    ll num[27],ud[27];
    ll t[N],A[N],B[N],l[N];
    vector<ll> w[27];
    ll hw[27];
    bool cmp1(ll x,ll y){
    	return q1[x]<q1[y];
    }
    bool cmp2(ll x,ll y){
    	return q2[x]<q2[y];
    }
    ll lowbit(ll x){
    	return x&-x;
    }
    void add(ll x){
    	while(x<=n){
    		t[x]+=1;
    		x+=lowbit(x);
    	}
    }
    ll query(ll x){
    	ll sum=0;
    	while(x){
    		sum+=t[x];
    		x-=lowbit(x);
    	}
    	return sum;
    }
    signed main(){
    	n=read();
    	scanf("%s",a+1);
    	for (int i=1;i<=2*n;i++) num[a[i]-'a'+1]++;
    	for (int i=1;i<=2*n;i++){
    		ud[a[i]-'a'+1]++;
    		if(ud[a[i]-'a'+1]<=num[a[i]-'a'+1]/2){
    			q1[++head1]=a[i]-'a'+1;
    			ans+=i-head1;
    		} else q2[++head2]=a[i]-'a'+1;
    	}
    	for (int i=1;i<=n;i++) A[i]=i,B[i]=i;
    	sort(A+1,A+1+n,cmp1);
    	sort(B+1,B+1+n,cmp2);
    	for (int i=1;i<=n;i++) w[q1[A[i]]].push_back(A[i]);
    	for (int i=1;i<=26;i++) sort(w[i].begin(),w[i].end());
    	for (int i=1;i<=n;i++) A[i]=w[q1[A[i]]][hw[q1[A[i]]]++];
    	for (int i=1;i<=26;i++) w[i].clear(),hw[i]=0;
    	for (int i=1;i<=n;i++) w[q2[i]].push_back(i);
    	for (int i=1;i<=26;i++) sort(w[i].begin(),w[i].end());
    	for (int i=1;i<=n;i++) l[A[i]]=w[q2[B[i]]][hw[q2[B[i]]]++];
    	for (int i=1;i<=n;i++){
    		ans+=(i-1-query(l[i]));
    		add(l[i]);
    	}
    	cout<<ans<<"\n";
    }
    
    • 1

    信息

    ID
    10860
    时间
    1000ms
    内存
    512MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者