模拟赛的题

这里,模拟赛的题分 \(3\) 类:

  • \(1\),我赛时 AC,但是认为有价值的。

  • \(2\),我赛后独立 AC,认为有价值的。平常,是我脑子比赛时或多或少出了问题的

  • \(3\),我赛后看题解 AC,认为有价值的。

loj 3513

类别:\(2\)

重新定义一下「平衡的」子集。设你选了 \(A_1,\cdots ,A_k\) 行,每行选 \(l_{A_i}\sim r_{A_i}\) 列(满足 \(3\))。

  • 都有草。

  • \(A_i\) 连续,满足 \([l_{A_{i}},r_{A_i}]∩[l_{A_{i-1}},r_{A_i-1}]\neq \emptyset\)

  • \(l\) 先减后增,\(r\) 反之。

\(dp_{l,r,a,b}\) 表示这行选了 \([l,r]\)\(l,r\) 现在是增还是减。

转移可以用(二维)前缀和优化。

点击查看代码
#include <bits/stdc++.h>

using namespace std;

#define de(x) cout<<#x<<"="<<x<<endl

using ll = long long;

const int N = 155;
const ll mod = 1e9+7;

int n;
char c[N][N];
int pf[N][N];
ll dp[N][N][2][2],sum[N][N][2][2];

ll s(int fa,int fb,int x1,int x2,int y1,int y2){
	return (mod+sum[x2][y2][fa][fb]-sum[x2][y1-1][fa][fb]-sum[x1-1][y2][fa][fb]+sum[x1-1][y1-1][fa][fb])%mod;
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);

	cin>>n;
	for (int i=1; i<=n; i++){
		for (int j=1; j<=n; j++){
			cin>>c[i][j];
			pf[i][j]=pf[i][j-1]+(c[i][j]=='G');
		}
	}
	ll ans=0;
	for (int i=1; i<=n; i++){
		memset(sum,0,sizeof sum);
		for (int l=1; l<=n; l++){
			for (int r=1; r<=n; r++){
				for (int fa=0; fa<2; fa++){
					for (int fb=0; fb<2; fb++){
						sum[l][r][fa][fb]=sum[l-1][r][fa][fb]+sum[l][r-1][fa][fb]-sum[l-1][r-1][fa][fb]+dp[l][r][fa][fb];
						sum[l][r][fa][fb]%=mod;
						(sum[l][r][fa][fb]+=mod)%=mod;
					}
				}
			}
		}
		memset(dp,0,sizeof dp);
		for (int l=1; l<=n; l++){
			for (int r=l; r<=n; r++){
				if (pf[i][r]-pf[i][l-1]!=r-l+1){
					continue;
				}
				(dp[l][r][0][0]+=1)%=mod;
				(dp[l][r][0][0]+=s(0,0,l,r,l,r))%=mod;
				(dp[l][r][0][1]+=s(0,0,l,r,r+1,n))%=mod;
				(dp[l][r][0][1]+=s(0,1,l,r,r,n))%=mod;
				(dp[l][r][1][0]+=s(0,0,1,l-1,l,r))%=mod;
				(dp[l][r][1][0]+=s(1,0,1,l,l,r))%=mod;
				(dp[l][r][1][1]+=s(0,1,1,l-1,r,n))%=mod;
				(dp[l][r][1][1]+=s(1,0,1,l,r+1,n))%=mod;
				(dp[l][r][1][1]+=s(1,1,1,l,r,n))%=mod;
				(dp[l][r][1][1]+=s(0,0,1,l-1,r+1,n))%=mod;
				(ans+=dp[l][r][0][0]+dp[l][r][0][1]+dp[l][r][1][0]+dp[l][r][1][1])%=mod;
			}
		}
	}
	cout<<ans<<endl;
	return 0;
}

// don't waste time!!!

loj 2743

类别:\(2\)。简单题啊,赛时没有看。

类似的题:12

先把 \(a\) 排序。

\(dp_{i,j,len,c}\)\(i\) 个数确定了,\(j\) 个段,\(len\) 长度,\(c\) 个端点确定了(\(0/1/2\))。

转移:

  • 新的长度是 \(len+(a_{i+1}-a_i)\times (2j-c)\)

  • 新建一段,单独成段。

  • 连接两段。

  • 接在另一段上(左右均可)。

  • 单独成段,钦定为端点。

  • 接在另一段上,钦定为端点。

点击查看代码
#include <bits/stdc++.h>

using namespace std;

#define de(x) cout<<#x<<"="<<x<<endl

using ll = long long;

const int N = 1e2+2;
const int L = 1e3+3;
const ll mod = 1e9+7;

ll n,l,a[N];
ll dp[N][N][L][3];

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);

	cin>>n>>l;
	for (int i=1; i<=n; i++){
		cin>>a[i];
	}
	if (n==1){
		cout<<1<<endl;
		return 0;
	}
	sort(a+1,a+1+n);
	dp[0][0][0][0]=1;
	for (int i=0; i<n; i++){
		for (int j=0; j<=i; j++){
			for (int k=0; k<=l; k++){
				for (int c=0; c<=2; c++){
					ll nw=k+(a[i+1]-a[i])*(2*j-c);
					if (nw>l){
						continue;
					}
					(dp[i+1][j+1][nw][c]+=dp[i][j][k][c]*(j+1-c))%=mod;
					if (j>1){
						(dp[i+1][j-1][nw][c]+=dp[i][j][k][c]*(j-1))%=mod;
					}
					if (j>0){
						(dp[i+1][j][nw][c]+=dp[i][j][k][c]*(2*j-c))%=mod;
					}
					if (c<2){
						(dp[i+1][j+1][nw][c+1]+=dp[i][j][k][c]*(2-c))%=mod;
						if (j){
							(dp[i+1][j][nw][c+1]+=dp[i][j][k][c]*(2-c))%=mod;
						}
					}
				}
			}
		}
	}
	ll ans=0;
	for (int i=0; i<=l; i++){
		(ans+=dp[n][1][i][2])%=mod;
	}
	cout<<ans<<endl;
	return 0;
}

// don't waste time!!!

loj 3576

类别:\(2\)

\(dp_{l,r,f}\) 代表还有 \(l\) 个小的,\(r\) 个大的的期望 HILO 次数,上一次是 \(f\)\(f=0\) 表示 LO,反之亦然)。

每一个数的被选概率是 \(\frac{1}{l+r}\)

\(dp_{0,l,r}=\displaystyle \frac{\sum_{l'<l}dp_{0,l',k}+\sum_{r'<r}dp_{1,l,r'}}{l+r}\)

\(dp_{1,l,r}=\displaystyle \frac{\sum_{l'<l}dp_{0,l',k}+\sum_{r'<r}dp_{1,l,r'}}{l+r}+\frac{l}{l+r}\)

下一个答案可以从上一个答案得到,因此可以优化为 \(O(N^2)\)

点击查看代码
#include <bits/stdc++.h>

using namespace std;

#define de(x) cout<<#x<<"="<<x<<endl

using ll = long long;

const int N = 5e3+3;
const ll mod = 1e9+7;

ll pw(ll a,ll b){
	ll res=1;
	a%=mod;
	while (b){
		if (b&1){
			res=res*a%mod;
		}
		b>>=1;
		a=a*a%mod;
	}
	return res;
} 

ll inv(ll x){
	return pw(x,mod-2);
}

int n,x;
int dp[N][N][2],s0[N],s1[N],iv[N];

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);

	cin>>n>>x;
	for (int i=1; i<=n; i++){
		iv[i]=inv(i);
	}
	for (int l=0; l<=x; l++){
		for (int r=0; r<=n-x; r++){
			dp[l][r][0]=1ll*(s0[l]+s1[r])*iv[l+r]%mod;
			dp[l][r][1]=1ll*(s0[l]+s1[r]+l)*iv[l+r]%mod;
			(s1[r]+=dp[l][r][0])%=mod;
			(s0[l]+=dp[l][r][1])%=mod;
		}
	}
	ll ans=1;
	for (ll i=1; i<=n; i++){
		(ans*=i)%=mod;
	}
	cout<<ans*dp[x][n-x][0]%mod<<endl;
	return 0;
}

// don't waste time!!!

CF 575A

类别:\(2\)。没打模拟赛。

分段,矩阵快速幂,线段树。简单题。但是挂了很多次。

  • cin 没有 scanf 快。

  • 矩阵不要写反。

  • 不要忘开 long long!

点击查看代码
#include <bits/stdc++.h>

using namespace std;

#define de(x) cout<<#x<<"="<<x<<endl

using ll = long long;

const int N = 2;
const int M = 5e4+4;

ll mod;

struct matrix {
	int mat[N][N];
	matrix(){
		mat[0][0]=mat[0][1]=mat[1][0]=mat[1][1]=0;
	}
	void init(int f){
		memset(mat,0,sizeof mat);
		for (int i=0; i<N; i++){
			mat[i][i]=f*1;
		}
	}
	matrix operator * (const matrix &a){
		matrix res;
		res.init(0);
		for (int i=0; i<N; i++){
			for (int j=0; j<N; j++){
				for (int k=0; k<N; k++){
					(res.mat[i][j]+=1ll*a.mat[i][k]*mat[k][j]%mod)%=mod;
				}
			}
		}
		return res;
	}
	matrix operator ^ (ll x){
		matrix res;
		res.init(1);
		matrix a;
		for (int i=0; i<N; i++){
			for (int j=0; j<N; j++){
				a.mat[i][j]=mat[i][j];
			}
		}
		while (x){
			if (x&1){
				res=res*a;
			}
			a=a*a;
			x>>=1;
		}
		return res;
	}
} x[M<<1],tmp[M<<1],a[M<<1];

matrix dat[M<<2];
void build(int k,int l,int r,int p,matrix ad){
	if (l==r){
		dat[k]=ad;
		return;
	}
	int mid=l+r>>1;
	if (p<=mid){
		build(k<<1,l,mid,p,ad);
	}
	else{
		build(k<<1|1,mid+1,r,p,ad); 
	}
	dat[k]=(dat[k<<1]*dat[k<<1|1]);
}
 
ll k,p,n,m;
ll s[M],b[M<<1];

struct Q {
	ll p,v,x;
	bool operator < (const Q &a) const {
		return p<a.p;
	}
} op[M<<1];

int main(){
	scanf("%lld%lld%lld",&k,&p,&n);
	mod=p;
	for (int i=0; i<n; i++){
		scanf("%lld",&s[i]);
		s[i]%=p;
	}
	s[n]=s[0];
	for (int i=1; i<=n; i++){
		x[i].mat[0][0]=0;
		x[i].mat[0][1]=1;
		x[i].mat[1][0]=s[i-1];
		x[i].mat[1][1]=s[i];
		build(1,1,n,i,x[i]);
		tmp[i]=x[i];
	}
	scanf("%lld",&m);
	matrix al=dat[1];
	for (int i=1; i<=m; i++){
		scanf("%lld%lld",&op[i].p,&op[i].v);
		op[i].v%=mod;
		op[i+m]=op[i];
		op[i+m].p++;
		op[i].x=1;
	}
	m<<=1;
	sort(op+1,op+1+m);
	while (op[m].p>k){
		m--;
	}
	ll kg=k/n,cur=0;
	for (int i=1; i<=m; ){
		int j=i;
		while (j<m && (op[j+1].p-1)/n==(op[i].p-1)/n){
			j++;
		}
		for (int k=i; k<=j; k++){
			int gk=(op[k].p-1)%n+1;
			tmp[gk].mat[1][op[k].x]=op[k].v;
			build(1,1,n,gk,tmp[gk]);
		}
		if ((op[j].p-1)/n==kg){
			break;
		}
		a[++cur]=dat[1];
		b[cur]=(op[j].p-1)/n;
		for (int k=i; k<=j; k++){
			int gk=(op[k].p-1)%n+1;
			tmp[gk]=x[gk];
			build(1,1,n,gk,x[gk]);
		}
		i=j+1;
	}
	matrix ans;
	ans.init(1);
	ll lst=0;
	for (int i=1; i<=cur; i++){
		ans=ans*(al^(b[i]-lst));
		ans=ans*a[i];
		lst=b[i]+1;
	}
	ans=ans*(al^(kg-lst));
	for (int i=1; i<=k%n; i++){
		ans=ans*tmp[i];
	}
	printf("%d\n",ans.mat[0][1]);
	return 0;
}

// don't waste time!!!

loj 2550

类别:\(1\)。用时 \(3\)h。

评价:打表猜结论!

arc 157f

类别:\(2\)。有两处没有开 long long!

单独的题解

待更!!!

posted @ 2023-08-08 15:50  SFlyer  阅读(34)  评论(0编辑  收藏  举报