P8908 [USACO22DEC] Palindromes P

Solution

模拟赛的题,死在了复杂度分析上。我还是太菜了。

先考虑暴力的做法。

\(\texttt{G}\)\(1\)\(\texttt{H}\)\(0\)

假设枚举到的区间为 \([L,R]\),有 \(k\)\(1\),位置为 \(a_{1\sim k}\),满足其为回文串的充要条件是 \(1\) 是对称的。

\([L,R]\) 长度为偶数且 \(1\) 的个数为奇数时显然是无解的。

要满足交换的次数最少,则一定是 \(a_1\)\(a_k\) 交换后关于中心对称,\(a_2\)\(a_{k-1}\) 后关于中心对称等。贡献为 \(| a_i-L-(R-a_{k-i+1})|=| a_i+a_{k-i+1}-L-R|\),即 \(i\)\(k-i+1\) 两个分别在中间的两侧。

每次求可以固定 \(L\),让 \(R\) 往右枚举,把为 \(1\) 的位置记录下来。复杂度 \(\mathcal{O(n^3)}\)

正解:

\(k\) 为奇数,可以固定第 \(\lfloor\frac{k+1}{2}\rfloor\) 的数,偶数同理。每次向两边各扩展一个 \(1\),设分别为 \(a_l,a_r\)。那么 \(L \in (a_{l-1},a_l]\)\(R \in [a_r,a_{r+1})\)

可以直接枚举 \(L,R\),对于每个 \(L,R\) 只会被枚举一次。因为 \(a_l,a_r\) 中点只有一个(显然的),它只会被枚举到一次,所以 \(L \in (a_{l-1},a_l]\)\(R \in [a_r,a_{r+1})\) 也只会被枚举到一次。

拿树状数组维护有多少个数比 \(L+R\) 大以及它们的和,有多少个数比 \(L+R\) 小以及它们的和。分别计算贡献即可。复杂度 \(\mathcal{O(n^2\log n)}\)

Code

#include<bits/stdc++.h>
#define IOS cin.tie(0),cout.tie(0),ios::sync_with_stdio(0)
#define ll long long
#define db double
#define pb push_back
#define eb emplace_back
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define PLL pair<ll,ll>
#define PII pair<int,int>
#define I inline
#define Tp template<typename Tt>
#define Ts template<typename Tt,typename ...args>
#define lb(x) ((x)&(-x))
using namespace std;
const int N=7500+20,M=1e5+20;
const ll INF=1ll<<60,mod=998244353;
namespace H_H{
	int n,a[N],b[N],cnt;
	struct BIT{
		ll s[N<<1],p[N<<1];
		inline void clear(){MS(s,0);MS(p,0);}
		inline void add(int x){
			int tp=x;
			for(;x<=2*n;x+=lb(x)) s[x]+=tp,p[x]+=1;
		}
		inline PLL query(int x){
			ll ans=0,Ans=0;
			for(;x;x-=lb(x)) ans+=s[x],Ans+=p[x];
			return {ans,Ans};
		}
	}bit;
	PLL operator - (const PLL xx,const PLL yy){
		return {xx.first-yy.first,xx.second-yy.second};
	}
	inline void input(){
		char ch;
		while(cin>>ch) a[++n]=ch=='G';
	}
	int main(){
		input();
		ll ans=0;
		for(int l=n;l;l--){
			cnt=0;
			for(int r=l;r<=n;r++){
				if(a[r]) b[++cnt]=r;
				if((r-l)&1 && cnt&1){//无解
					ans--;
					continue;
				}
				if(cnt&1) ans+=abs(((l+r)>>1)-b[(cnt>>1)+1]);
			}
		}
		b[cnt+1]=n+1;
		for(int i=1;i<cnt;i++){//k 为偶数
			bit.clear();
			for(int l=i,r=i+1;l>=1 && r<=cnt;l--,r++){
				bit.add(b[l]+b[r]);
				for(int L=b[l-1]+1;L<=b[l];L++){
					for(int R=b[r];R<=b[r+1]-1;R++){
						int num=L+R;
						PLL num_1=bit.query(num);
						PLL num_2=bit.query(2*n)-num_1;
						ans+=(num_1.second-num_2.second)*num+num_2.first-num_1.first;
					}
				}
			}
		}
		for(int i=2;i<cnt;i++){//k 为奇数
			bit.clear();
			for(int l=i-1,r=i+1;l>=1 && r<=cnt;l--,r++){
				bit.add(b[l]+b[r]);
				for(int L=b[l-1]+1;L<=b[l];L++){
					for(int R=b[r];R<=b[r+1]-1;R++){
						if((L-R)&1) continue;
						int num=L+R;
						PLL num_1=bit.query(num);
						PLL num_2=bit.query(2*n)-num_1;
						ans+=(num_1.second-num_2.second)*num+num_2.first-num_1.first;
					}
				}
			}
		}
		cout<<ans<<"\n";
		return 0;
	}
}
int main(){
	IOS;H_H::main();
	return 0;
}
posted @ 2025-11-30 16:20  tyh_27  阅读(1)  评论(0)    收藏  举报