2025国庆Day3

模拟赛

T1

对每个ai开个桶分别算答案即可

注意long long

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<bits/stdc++.h>
#define int long long
#define jiaa(a,b) {a+=b;if(a>=MOD) a-=MOD;}
#define jian(a,b) {a-=b;if(a<0) a+=MOD;}
using namespace std;
int ksm(int a,int b,int p){
	if(b==0) return 1;
	if(b==1) return a%p;
	int c=ksm(a,b/2,p);
	c=c*c%p;
	if(b%2==1) c=c*a%p;
	return c%p;	
}
inline int read()
{
	int 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;
}
int a[1000005],mm[1000005],sum[1000005];
signed main()
{
	freopen("type.in", "r", stdin);
	freopen("type.out", "w", stdout);
	int n=read();
	for(int i=1;i<=n;i++) a[i]=read();
	int m=read();
	while(m--){
		int p=read();
		sum[1]++;
		sum[p+1]--;
	}
	sum[1]++;
	sum[n+1]--;
	for(int i=1;i<=n;i++) sum[i]+=sum[i-1];
	for(int i=1;i<=n;i++){
		mm[a[i]]+=sum[i];
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		ans^=(mm[i]*i);
	}
	cout<<ans<<'\n';
	return 0;
}

T2

维护m个指针

倒着枚举l

p1~pm维护第i个字符已匹配的下标

每次匹配修改一个前缀

复杂度O(n)

另外可考虑:

image

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<bits/stdc++.h>
#define int long long
#define jiaa(a,b) {a+=b;if(a>=MOD) a-=MOD;}
#define jian(a,b) {a-=b;if(a<0) a+=MOD;}
using namespace std;
int ksm(int a,int b,int p){
	if(b==0) return 1;
	if(b==1) return a%p;
	int c=ksm(a,b/2,p);
	c=c*c%p;
	if(b%2==1) c=c*a%p;
	return c%p;	
}
inline int read()
{
	int 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;
}
int s[1000005],t[1000005],p[1000005],tt[1000005],ss[1000005];
signed main()
{
	freopen("jasmine.in", "r", stdin);
	freopen("jasmine.out", "w", stdout);
	int T=read();
	while(T--){
		int n=read(),m=read();
		for(int i=1;i<=m;i++){
			p[i]=1000000000;
		} 
		for(int i=1;i<=n;i++) ss[i]=0;
		for(int i=1;i<=n;i++){
			s[i]=read();
			if(s[i]<=1000000) tt[s[i]]=0;
		} 
		for(int i=1;i<=m;i++){
			t[i]=read();
		}
		for(int i=1;i<=n;i++){
			if(s[i]>1000000) continue;
			ss[i]=tt[s[i]];
			tt[s[i]]=i;
		}
		int minn=1000000000,minl=0,minr=0;
		for(int i=n;i;i--){
			int l=i;
			int f=0;
			for(int j=1;j<=m;j++){
//				cout<<f<<'\n';
				if(f) break;
				f=1;
				while(1){
					int nw=tt[t[j]];
					if(p[j]!=1000000000) nw=ss[p[j]];
//					cout<<nw<<'\n';
					if(l<=nw){
						f=0;
						p[j]=nw;
					}
					else break;
				}
				l=p[j]+1;
//				cout<<l<<'\n';
			}
			if(p[m]<=n&&p[m]-i+1<=minn){
				minn=p[m]-i+1;
				minl=i;
				minr=p[m];
			}
		}
		if(minn==1000000000) cout<<-1<<'\n';
		else cout<<minl<<' '<<minr<<'\n';
	}
	return 0;
}

T3

设dpi,j表示i子树内钦定返祖j次的方案数

将相邻向北的点对连边,形成若干条链

合并子树时方案数image

然后新加一个点,这个点相当于加入到任意一条链中,或者新增一条链

最后把钦定变成恰好,容斥一下

容斥大概如下

6bf9ef4de4c2b82b1f911d65217fbdca

牛逼的容斥笔记

T4

牛逼的题

先考虑k=2

image

挖掘性质

image

image

image

image

image

DP

CF392B

fi,x,y表示前i个盘,从x到y的代价

容易转移

P2331

dpi,j,0~4表示第i行,选了j个矩阵

这一行的两个数{

  1. 没有元素被选择

  2. 第一列的元素在子矩阵中

  3. 第二列的元素在子矩阵中

  4. 两列元素在同一个子矩阵中

  5. 两列元素在不同子矩阵中
    }

分别转移即可

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<bits/stdc++.h>
#define int long long
#define jiaa(a,b) {a+=b;if(a>=MOD) a-=MOD;}
#define jian(a,b) {a-=b;if(a<0) a+=MOD;}
using namespace std;
int ksm(int a,int b,int p){
	if(b==0) return 1;
	if(b==1) return a%p;
	int c=ksm(a,b/2,p);
	c=c*c%p;
	if(b%2==1) c=c*a%p;
	return c%p;	
}
inline int read()
{
	int 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;
}
int dp[105][105][5];
signed main()
{
	//freopen("filename.in", "r", stdin);
	//freopen("filename.out", "w", stdout);
	int n=read(),m=read(),k=read();
	memset(dp,-0x3f,sizeof(dp));
	for(int i=0;i<=n;i++){
		for(int j=0;j<=k;j++) dp[i][j][0]=0;
	}
	if(m==1){
		for(int i=1;i<=n;i++){
			int a=read();
			for(int j=1;j<=k;j++){
				dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1]);
				dp[i][j][1]=max(dp[i-1][j-1][0],dp[i-1][j][1])+a;
			}
		}
		cout<<max(dp[n][k][0],dp[n][k][1])<<'\n';
	}
	else{
		for(int i=1;i<=n;i++){
			int a=read(),aa=read();
			for(int j=1;j<=k;j++){
				dp[i][j][0]=max(max(dp[i-1][j][0],dp[i-1][j][1]),max(dp[i-1][j][2],max(dp[i-1][j][3],dp[i-1][j][4])));
				dp[i][j][1]=max(max(dp[i-1][j-1][0],dp[i-1][j][1]),max(dp[i-1][j-1][2],max(dp[i-1][j][3],dp[i-1][j-1][4])))+a;
				dp[i][j][2]=max(max(dp[i-1][j-1][0],dp[i-1][j-1][1]),max(dp[i-1][j][2],max(dp[i-1][j][3],dp[i-1][j-1][4])))+aa;
				dp[i][j][3]=max(max(dp[i-1][j-1][2],dp[i-1][j-1][1]),dp[i-1][j][3])+a+aa;
				if(i>1) dp[i][j][3]=max(dp[i][j][3],dp[i-1][j-2][4]+a+aa);
				dp[i][j][4]=max(max(dp[i-1][j-1][0],dp[i-1][j-1][1]),max(dp[i-1][j-1][2],max(dp[i-1][j-1][3],dp[i-1][j][4])))+a+aa;
			}
		}
		cout<<max(max(dp[n][k][0],dp[n][k][1]),max(dp[n][k][2],max(dp[n][k][3],dp[n][k][4])))<<'\n';
	}
	return 0;
}

CF607B

fi,j表示消除[i,j]的最小代价

经典区间DP

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<bits/stdc++.h>
#define int long long
#define jiaa(a,b) {a+=b;if(a>=MOD) a-=MOD;}
#define jian(a,b) {a-=b;if(a<0) a+=MOD;}
using namespace std;
int ksm(int a,int b,int p){
	if(b==0) return 1;
	if(b==1) return a%p;
	int c=ksm(a,b/2,p);
	c=c*c%p;
	if(b%2==1) c=c*a%p;
	return c%p;	
}
inline int read()
{
	int 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;
}
int dp[505][505],a[505];
signed main()
{
	//freopen("filename.in", "r", stdin);
	//freopen("filename.out", "w", stdout);
	int n=read();
	memset(dp,0x3f,sizeof(dp));
	for(int i=1;i<=n;i++){
		a[i]=read();
		dp[i][i]=1;
		if(i>1){
			if(a[i]==a[i-1]) dp[i-1][i]=1;
			else dp[i-1][i]=2;
		}
	}
	for(int l=3;l<=n;l++){
		for(int ll=1;ll<=n;ll++){
			int r=ll+l-1;
//			if(l<=2) cout<<ll<<' '<<r<<' '<<dp[ll][r]<<'\n';
			if(r>n) break;
			for(int k=ll;k<r;k++){
				dp[ll][r]=min(dp[ll][r],dp[ll][k]+dp[k+1][r]);
			}
			if(a[ll]==a[r]) dp[ll][r]=min(dp[ll][r],dp[ll+1][r-1]);
		}
	}
	cout<<dp[1][n]<<'\n';
	return 0;
}

CF571B

相当于要求选择k条链

求出k条链最大值减最小值最小能是多少

容易看出每条链不交

image

CF703E

b为k的倍数当且仅当gcd(b,k)=k

fi,j表示前i个数gcd=j的最小元素和

而gcd(Bb,k)=gcd(b,k)gcd(b,k/gcd(B,k))

P1169

对(i+j)奇数的点取反

变成颜色全相同的最大子矩阵/正方形

子矩阵就对每个点求出往上最大延伸长度

据此算出往左往右第一个比他小的位置

计算答案

正方形就设fi,j表示以i,j左上角最大边长

若si,j=i-1,j=i,j-1=i-1,j-1

则fi,j=max(f+1)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<bits/stdc++.h>
#define int long long
#define jiaa(a,b) {a+=b;if(a>=MOD) a-=MOD;}
#define jian(a,b) {a-=b;if(a<0) a+=MOD;}
using namespace std;
int ksm(int a,int b,int p){
	if(b==0) return 1;
	if(b==1) return a%p;
	int c=ksm(a,b/2,p);
	c=c*c%p;
	if(b%2==1) c=c*a%p;
	return c%p;	
}
inline int read()
{
	int 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;
}
int a[2005][2005],dp[2005][2005],h[2005][2005],l[2005][2005],r[2005][2005];
signed main()
{
	//freopen("filename.in", "r", stdin);
	//freopen("filename.out", "w", stdout);
	int n=read(),m=read();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			a[i][j]=read();
			if((i+j)%2==0){
				if(a[i][j]) a[i][j]=0;
				else a[i][j]=1;
			}
			h[i][j]=dp[i][j]=1;
			l[i][j]=r[i][j]=j;
		}
	}
	int ans=1;
	for(int i=n-1;i;i--){
		for(int j=m-1;j;j--){
			if(a[i][j]==a[i+1][j]&&a[i][j]==a[i][j+1]&&a[i][j]==a[i+1][j+1]){
				dp[i][j]=max(min(dp[i+1][j],min(dp[i][j+1],dp[i+1][j+1]))+1,dp[i][j]);
//				cout<<i<<' '<<j<<'\n';
//				cout<<dp[i][j]<<'\n';
//				cout<<a[i][j]<<' '<<a[i+1][j]<<' '<<a[i][j+1]<<' '<<a[i+1][j+1]<<'\n';
				ans=max(ans,dp[i][j]);
			}
		}
	}
	cout<<ans*ans<<'\n';
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(j>1&&a[i][j-1]==a[i][j]) l[i][j]=l[i][j-1];
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=m;j;j--){
			if(j<m&&a[i][j+1]==a[i][j]) r[i][j]=r[i][j+1];
		}
	}
	ans=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(i>1&&a[i][j]==a[i-1][j]){
				l[i][j]=max(l[i][j],l[i-1][j]);
				r[i][j]=min(r[i-1][j],r[i][j]);
				h[i][j]=h[i-1][j]+1;
			}
			ans=max(ans,(r[i][j]-l[i][j]+1)*h[i][j]);
		}
	}
	cout<<ans<<'\n';
	return 0;
}

QOJ8933

fi,j表示i个事件,剩j个1分,最多0分的数量

此时2分数量=si-j

简单转移

QOJ9312

期望DP

image

QOJ8528

环上的线相交相当于区间相交

数据随机

答案不会太大(<900)

gi,j表示i,j最大匹配

满足单调性

fi,j表示满足gi,k=j的最小的k

转移考虑i是否匹配

若匹配,那么更新就是从 ri 继承过来加上 gi,ri 的答案

否则就是从 i + 1 继承

计数

GYM105336

容易发现如果一个 ai 和 bj 匹配了,那么 ai 后的元素与 bj 前的元素匹配对答案就不会产生改变了

考虑 答案 k 被确定时,方案可以简单算出

令 fi,j 表示前 i 个 a 匹配了 j 个 b 的方案数

每次枚举选不选即可转移

不难发现对于一个权值为 w 的方案,恰好在 k = 1~w 都被计算了一次

直接对所有 k 的答案求和即可得到所有匹配的权值和。

P2592

转化成网格计数

要求y-x极差<=k

image

(对称计算答案就是用类似卡特兰数的方法

卡特兰数公式:C(2n,n)-C(2n,n-2)

这个公式就是通过对称得来的)

复杂度O(n+m+k)

posted @ 2025-10-04 17:18  gbrrain  阅读(23)  评论(0)    收藏  举报