2 条题解

  • 0
    @ 2025-10-8 17:03:36

    首先判断能否构成回文串 对于前 ⌊n/2⌋个字符,若每种字符出现次数恰好为对应的一半, 那么就把右半部分对称成左半部分的样子即可,若左边相邻两个字符交换, 逆序对个数只会 ±1,而右半部分的逆序对只会 ∓1,恰好抵消 否则贪心的将右边靠左且多的字符往左边移,这样影响的逆序对数是最少的 然后树状数组求逆序对即可

    #include <bits/stdc++.h>
    using namespace std;
    #define pb push_back
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define lp p << 1
    #define rp p << 1 | 1
    #define mid ((l + r) >> 1)
    #define ll long long
    #define db double
    #define rep(i,a,b) for(int i=a;i<b;i++)
    #define per(i,a,b) for(int i=b-1;i>=a;i--)
    #define Edg int cnt=1,head[N],to[N*2],ne[N*2];void addd(int u,int v){to[++cnt]=v;ne[cnt]=head[u];head[u]=cnt;}void add(int u,int v){addd(u,v);addd(v,u);}
    #define Edgc int cnt=1,head[N],to[N*2],ne[N*2],c[N*2];void addd(int u,int v,int w){to[++cnt]=v;ne[cnt]=head[u];c[cnt]=w;head[u]=cnt;}void add(int u,int v,int w){addd(u,v,w);addd(v,u,w);}
    #define es(u,i,v) for(int i=head[u],v=to[i];i;i=ne[i],v=to[i])
    
    const int N = 1e5 + 7;
    char s[N];
    int cnt[28], pos[28][N], half[28], a[N], b[N], n, tree[N];
    inline int lowbit(int x) { return x & -x; }
    void add(int x) {
    	assert(x);
    	for (int i = x; i <= n; i += lowbit(i)) tree[i]++;
    }
    int query(int x) {
    	int ans = 0;
    	for (int i = x; i; i -= lowbit(i)) 
    		ans += tree[i]; 
    	return ans;
    }
    
    void solve() {
    	memset(cnt, 0, sizeof(cnt));
    	scanf("%s", s + 1);
    	n = strlen(s + 1);
    	memset(tree, 0, sizeof(int) * (n + 2));
    	rep (i, 1, n + 1) {
    		int c = s[i] - 'a';
    		cnt[c]++;
    		pos[c][cnt[c]] = i;
    	}
    	int tol = 0, mid_alp = -1;
    	rep (i, 0, 26) {
    		if (cnt[i] & 1) tol++, mid_alp = i;
    		half[i] = cnt[i] / 2;
    	}
    	if (n % 2 == 0) {
    		if (tol) { puts("Impossible"); return; }
    	} else if (tol != 1) {
    		puts("Impossible"); return;
    	}
    	int cur = 1;
    	int mi = n / 2;
    	rep (i, 1, mi + 1) {
    		while (!half[s[cur] - 'a']) cur++;
    		a[i] = cur; half[s[cur++] - 'a']--;
    	}
    	if (n & 1) {
    		a[mi + 1] = pos[mid_alp][cnt[mid_alp] / 2 + 1];
    		//assert(pos[mid_alp][cnt[mid_alp] / 2 + 1] == cnt[mid_alp] / 2 + 1);
    		per(i, 1, mi + 1) {
    			int c = s[a[mi - i + 1]] - 'a';
    			a[i + mi + 1] = pos[c][cnt[c]--];
    		}
    	} else {
    		per(i, 1, mi + 1) {
    			int c = s[a[mi - i + 1]] - 'a';
    			a[i + mi] = pos[c][cnt[c]--];
    		}
    	}
    	rep (i, 1, n + 1) b[a[i]] = i;
    	long long ans = 0;
    	per (i, 1, n + 1) ans += query(b[i]), add(b[i]);
    	printf("%lld\n", ans);
    }
    
    int main() {
    	int T;
    	scanf("%d", &T);
    	while (T--)
    		solve();
    	return 0;
    }
    
    • 0
      @ 2025-10-8 17:03:22
      /*
      首先判断能否构成回文串
      对于前 ⌊n/2⌋个字符,若每种字符出现次数恰好为对应的一半,
      那么就把右半部分对称成左半部分的样子即可,若左边相邻两个字符交换,
      逆序对个数只会 ±1,而右半部分的逆序对只会 ∓1,恰好抵消
      否则贪心的将右边靠左且多的字符往左边移,这样影响的逆序对数是最少的
      然后树状数组求逆序对即可
      */
      #include <bits/stdc++.h>
      using namespace std;
      #define pb push_back
      #define fi first
      #define se second
      #define pii pair<int, int>
      #define lp p << 1
      #define rp p << 1 | 1
      #define mid ((l + r) >> 1)
      #define ll long long
      #define db double
      #define rep(i,a,b) for(int i=a;i<b;i++)
      #define per(i,a,b) for(int i=b-1;i>=a;i--)
      #define Edg int cnt=1,head[N],to[N*2],ne[N*2];void addd(int u,int v){to[++cnt]=v;ne[cnt]=head[u];head[u]=cnt;}void add(int u,int v){addd(u,v);addd(v,u);}
      #define Edgc int cnt=1,head[N],to[N*2],ne[N*2],c[N*2];void addd(int u,int v,int w){to[++cnt]=v;ne[cnt]=head[u];c[cnt]=w;head[u]=cnt;}void add(int u,int v,int w){addd(u,v,w);addd(v,u,w);}
      #define es(u,i,v) for(int i=head[u],v=to[i];i;i=ne[i],v=to[i])
      
      const int N = 1e5 + 7;
      char s[N];
      int cnt[28], pos[28][N], half[28], a[N], b[N], n, tree[N];
      inline int lowbit(int x) { return x & -x; }
      void add(int x) {
      	assert(x);
      	for (int i = x; i <= n; i += lowbit(i)) tree[i]++;
      }
      int query(int x) {
      	int ans = 0;
      	for (int i = x; i; i -= lowbit(i)) 
      		ans += tree[i]; 
      	return ans;
      }
      
      void solve() {
      	memset(cnt, 0, sizeof(cnt));
      	scanf("%s", s + 1);
      	n = strlen(s + 1);
      	memset(tree, 0, sizeof(int) * (n + 2));
      	rep (i, 1, n + 1) {
      		int c = s[i] - 'a';
      		cnt[c]++;
      		pos[c][cnt[c]] = i;
      	}
      	int tol = 0, mid_alp = -1;
      	rep (i, 0, 26) {
      		if (cnt[i] & 1) tol++, mid_alp = i;
      		half[i] = cnt[i] / 2;
      	}
      	if (n % 2 == 0) {
      		if (tol) { puts("Impossible"); return; }
      	} else if (tol != 1) {
      		puts("Impossible"); return;
      	}
      	int cur = 1;
      	int mi = n / 2;
      	rep (i, 1, mi + 1) {
      		while (!half[s[cur] - 'a']) cur++;
      		a[i] = cur; half[s[cur++] - 'a']--;
      	}
      	if (n & 1) {
      		a[mi + 1] = pos[mid_alp][cnt[mid_alp] / 2 + 1];
      		//assert(pos[mid_alp][cnt[mid_alp] / 2 + 1] == cnt[mid_alp] / 2 + 1);
      		per(i, 1, mi + 1) {
      			int c = s[a[mi - i + 1]] - 'a';
      			a[i + mi + 1] = pos[c][cnt[c]--];
      		}
      	} else {
      		per(i, 1, mi + 1) {
      			int c = s[a[mi - i + 1]] - 'a';
      			a[i + mi] = pos[c][cnt[c]--];
      		}
      	}
      	rep (i, 1, n + 1) b[a[i]] = i;
      	long long ans = 0;
      	per (i, 1, n + 1) ans += query(b[i]), add(b[i]);
      	printf("%lld\n", ans);
      }
      
      int main() {
      	int T;
      	scanf("%d", &T);
      	while (T--)
      		solve();
      	return 0;
      }
      
      • 1

      信息

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