8.21

不想补旧账了

Brooklyn Round 2 & NNOI Round 2 + 『MGVOI』Round 1 加强赛 未补

还是先把今天的写好吧 CZOI Round 6

大约迟了 \(1h\) 才开始打,场A : A+C,已补 A,B,C

A

P13788

当出现两个排列的时候,把其中一个看成有序的,映射到 \(1,2,3,4,...\) 上,在转换另一个是非常常见的思路

这道题可以转 \(a\) ,然后发现其连续的上升子序列都是合法的,统计一下每个上升子序列的长度即可

CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
const int maxn=1e6+5;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
}
int n;
int a[maxn],b[maxn];
int t[maxn];
int main(){
	read(n);
	for(int i=1;i<=n;i++) read(a[i]);
	int in;
	for(int i=1;i<=n;i++) read(in),t[in]=i;
	for(int i=1;i<=n;i++) a[i]=t[a[i]];
	int cnt=0;
	LL ans=0;
	for(int i=1;i<=n;i++){
		++cnt;
		if(a[i]>a[i+1]){
			ans+=1ll*cnt*(cnt+1)/2;
			cnt=0;
		}
	}
	printf("%lld",ans);
	return 0;
}
//^o^

B

我把它看成和了... 比C还高的通过率

每次做游戏的点都可以看做一个起点,它可以向上,下,左,右影响其它点

然后因为求最大每个点最大得分,动态规划一下就好了

\[f1[i][j]=max({f1[i-1][j]+k1,f1[i][j-1]+k2,f1[i][j]}) \]

这是左上点的转移

注意一下不同方位的转移需要不同的遍历顺序

CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int maxn=3e3+5;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
}
int p[maxn][maxn];
LL f1[maxn][maxn],f2[maxn][maxn],f3[maxn][maxn],f4[maxn][maxn];
ULL pw[maxn*maxn];
int n,m,q,k1,k2;
int main(){
	read(n),read(m),read(q),read(k1),read(k2);
	pw[0]=1;
	for(int i=1;i<=n*m;i++) pw[i]=pw[i-1]*131;
	int x,y,u;
	memset(p,0xc0,sizeof(p));
	memset(f1,0xc0,sizeof(f1));
	memset(f2,0xc0,sizeof(f2));
	memset(f3,0xc0,sizeof(f3));
	memset(f4,0xc0,sizeof(f4));
	while(q--){
		read(x),read(y),read(u);
		p[x][y]=max(p[x][y],u);
		f1[x][y]=f2[x][y]=f3[x][y]=f4[x][y]=p[x][y];
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			f1[i][j]=max({f1[i-1][j]+k1,f1[i][j-1]+k2,f1[i][j]});
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=m;j>=1;j--){
			f2[i][j]=max({f2[i-1][j]+k1,f2[i][j+1]+k2,f2[i][j]});
		}
	}
	for(int i=n;i>=1;i--){
		for(int j=1;j<=m;j++){
			f3[i][j]=max({f3[i+1][j]+k1,f3[i][j-1]+k2,f3[i][j]});
		}
	}
	for(int i=n;i>=1;i--){
		for(int j=m;j>=1;j--){
			f4[i][j]=max({f4[i+1][j]+k1,f4[i][j+1]+k2,f4[i][j]});
		}
	}
	ULL sum=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			LL ans=max({f1[i][j],f2[i][j],f3[i][j],f4[i][j]});
			sum+=ans*pw[(i-1)*m+j];
		}
	}
	printf("%llu",sum);
	return 0;
}
//^o^

C

感觉被我写的很麻烦,应该有更好的做法吧

\(\frac{n}{2}\) 的前缀开始,比较前后缀是否满足只有一个不相同

同时我们还需要找到这个不相同的位置,这里用双值哈希+二分做即可(单值没有试过,不过应该可以)

找到这个位置后,我们需要讨论到底是前面的改成后面的,还是后面的改成前面的

因为改完以后还有可能继续扩展,所以分别跑一次 \(KMP\) 求整个字符串的 \(border\) ,找最大值就好了

据说有人用模拟做出来了

CODE
#include<bits/stdc++.h>
#define fst first
#define sec second
#define mkp make_pair
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
typedef pair<LL,LL> pii;
const int maxn=1e6+5;
const int B1=131,mod1=998244353;
const int B2=233,mod2=1e9+7;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
}
char s[maxn];
int n;
pii h[maxn];
LL p1[maxn],p2[maxn];
int pi[maxn];
void hsh(){
	p1[0]=p2[0]=1;
	for(int i=1;i<=n;i++){
		h[i]=mkp((h[i-1].fst*B1+s[i])%mod1,(h[i-1].sec*B2+s[i])%mod2);
		p1[i]=p1[i-1]*B1%mod1,p2[i]=p2[i-1]*B2%mod2;
	}
}
pii get_hsh(int l,int r){
	return mkp((h[r].fst-h[l-1].fst*p1[r-l+1]%mod1+mod1)%mod1,\
			   (h[r].sec-h[l-1].sec*p2[r-l+1]%mod2+mod2)%mod2);
}
bool cmp(int l1,int r1,int l2,int r2){
	return get_hsh(l1,r1)==get_hsh(l2,r2);
}
int check(int p,int si){
	int l=0,r=si;
	int ans=si;
	while(l<=r){
		int mid=(l+r)>>1;
		if(cmp(1,mid,p,p+mid-1)) l=mid+1;
		else ans=mid,r=mid-1;
	}
	if(cmp(ans+1,si,p+ans,n)){
		return ans;
	}
	return 0;
}
int main(){
	scanf("%s",s+1);
	n=strlen(s+1);
	hsh();
	int ans=0,st=0;
	for(int i=n/2;i>=1;i--){
		if(ans=check(n-i+1,i)){
			st=n-i+1;
			break;
		}
	}
	char temp=s[ans];
	s[ans]=s[st+ans-1];
	int mx=0;
	for(int i=1,j=0;i<n;i++){
		while(j&&s[i+1]!=s[j+1]) j=pi[j];
		if(s[i+1]==s[j+1]) ++j;
		pi[i]=j-1;
	}
	//printf("%s\n",s+1);
	mx=max(mx,pi[n-1]+1);
	s[st+ans-1]=s[ans]=temp;
	for(int i=1,j=0;i<n;i++){
		while(j&&s[i+1]!=s[j+1]) j=pi[j];
		if(s[i+1]==s[j+1]) ++j;
		pi[i]=j-1;
	}
	mx=max(mx,pi[n-1]+1);
	//printf("%s\n",s+1);
	printf("%d",mx);
	return 0;
}
//^o^
posted @ 2025-08-21 20:04  huangems  阅读(9)  评论(0)    收藏  举报