【2024.08.15】NOIP2024暑假集训模拟赛(13)

【2024.08.15】NOIP2024暑假集训模拟赛(13)

T1

先找能构成回文的最长前缀和后缀(长度相同的),然后在任意一边的基础上扩展,看能否接一个回文串。

#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l);i<=(r);++i)
#define G(i,r,l) for(int i(r);i>=(l);--i)
#define int ll
using namespace std;
using ll = long long;
using ull = unsigned long long;
const int N=5e5+5;
const int P=1031;
char s[N];
ull h[N],g[N],p[N];
int T;
inline ull get1(int l,int r){ return (l<=r) ? h[r] - h[l-1] * p[r-l+1] : 0; }
inline ull get2(int l,int r){ return (l<=r) ? g[l] - g[r+1] * p[r-l+1] : 0; }
signed main(){
//	freopen("reverse.in","r",stdin); 
//	freopen("reverse.out","w",stdout);
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	p[0]=1; F(i,1,500000) p[i] = p[i-1] * P;
	cin>>T;
	F(o,1,T){
		cin>>(s+1); int n=strlen(s+1);
		h[0]=g[n+1]=0;
		F(i,1,n) h[i]=(h[i-1]*P+s[i]);
		G(i,n,1) g[i]=(g[i+1]*P+s[i]);
		if(h[n]==g[1]){ cout<<n<<"\n"; continue; }
		for(int i=1,j=n;i<=j;++i,--j){
			if(h[i]==g[j]) continue;
			int len1=0,len2=0;
			F(ed,i,j-1)	if(get1(i,ed) == get2(i,ed)) len1=ed-i+1; 
			G(st,j,i+1) if(get1(st,j) == get2(st,j)) len2=j-st+1;
			cout << max(len1,len2) + (i-1) * 2 << '\n';
			break;
		}
	}
	return fflush(0),0;
}

T2

对极差二分答案(显然)

重点是check, 记 \(f[i]\) 表示 前 \(i\) 座山在满足极差限制的前提下,最少的更改次数,其中强制第 \(i\) 座山不修改。

有转移:

\[f[i] = \min_{j=0 且 a[i]-a[j] \le x\times (i-j)}^{i-1} f[j] + (i-j-1) \]

最后判断是否存在 \(i \in [1,n],\ f[i]+(n-i) \le k.\)

时间复杂度 \(O(TN^2log A).\)

posted @ 2024-08-15 16:20  superl61  阅读(25)  评论(0)    收藏  举报