2022.9.20测试

一测330,原因T4是乱打else导致炸了。

T1:P2327 [SCOI2005]扫雷(黄)

T2:P1896 [SCOI2005] 互不侵犯(蓝)

T3:P2330 [SCOI2005]繁忙的都市(黄)

T4:2331 [SCOI2005]最大子矩阵(蓝)


T1:

记录 dpi,j,k 代表第 i 个未知格子,雷的状态为 j,上一个雷的状态为 k 的方案数。

那么要满足:

ai1=j+k+l其中l为第i2个未知格子上的雷情况,且:aij+k

那么就可以转移了

dpi,j,k+=dpi1,k,l

最后统计 j=01k=01dpn,j,k 即可。

#include<iostream>
#include<cstdio>
#define int long long
using namespace std;
const int N=1e4+5;
int n,a[N],dp[N][2][2];
signed main()
{
	freopen("sweeper.in","r",stdin);
	freopen("sweeper.out","w",stdout);
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
	if(a[1]||a[2])dp[1][1][0]=1;
	dp[1][0][0]=1;
	for(int i=2;i<=n;i++)
	{
		for(int j=0;j<2;j++)
		{
			for(int k=0;k<2;k++)
			{
				if(j+k>a[i])break;
				for(int l=0;l<2;l++)
				{
					if(j+k+l!=a[i-1])continue;
					dp[i][j][k]+=dp[i-1][k][l];
				}
			}
		}
	}
	int ans=0;
	for(int i=0;i<2;i++)for(int j=0;j<2;j++)if(i+j==a[n])ans+=dp[n][i][j];
	printf("%lld",ans);
	return 0;
}

T2:

经典状压模板,不讲了。

dpi,q,j 代表第 i 行,已放 q 个棋子,第 i 行状态为 j 的方案数。

首先同行国王不能互相攻击,所以 j(j<<1)=j(j<<1)=0

另外不同行的国王也不能互相攻击,设上一行的状态为 t,所以 jt=j(t<<1)=j(t>>1)=0

先预处理出来合法的 j,并用lowbit处理出来 numj,代表每个状态 j 有多少个国王。

最后进行dp转移。

dpi,q,j+=dpi1,qnumj,t

然后答案为 i=1(1<<n)1dpn,i,k

#include<iostream>
#include<cstdio>
#define int long long
using namespace std;
const int N=9;
int n,k,dp[N+1][N*N+1][1<<N],p[1<<N],vis[1<<N];
inline int lowbit(int x)
{
	return x&(-x);
}
void pre()
{
	for(int i=0;i<1<<n;i++)
	{
		if((i&(i<<1))||(i&(i>>1)))continue;
		vis[i]=1;
		int x=i;
		while(x)x-=lowbit(x),p[i]++;
	}
}
signed main()
{
	freopen("king.in","r",stdin);
	freopen("king.out","w",stdout);
	scanf("%lld%lld",&n,&k);
	pre();
	for(int i=0;i<1<<n;i++)if(vis[i])dp[1][p[i]][i]=1;
	for(int i=2;i<=n;i++)
	{
		for(int j=0;j<1<<n;j++)
		{
			if(!vis[j])continue;
			for(int t=0;t<1<<n;t++)
			{
				if(!vis[t])continue;
				if((j&t)||(j&(t<<1))||(j&(t>>1)))continue;
				for(int q=p[j]+p[t];q<=k;q++)dp[i][q][j]+=dp[i-1][q-p[j]][t];
			}
		}
	}
	int ans=0;
	for(int i=0;i<1<<n;i++)ans+=dp[n][k][i];
	printf("%lld",ans);
	return 0;
}

T3:

题看完以后就是个最小生成树,然后就没了

要求要所有点连通,且边最少,所以取 n1 条边。

然后要求取出的所有边的权值最大值最小,那么每次贪心取最小边,如果这个边连接的两个点已在一个子图,那么不能选取这条边。可以利用并查集判断两个点是否在一个子图。

实质上就是做最小生成树的工作。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e5+5;
int n,m,f[N];
struct node
{
	int from,to,data;
}a[N];
bool cmp(node fi,node se)
{
	return fi.data<se.data;
}
int afind(int x)
{
	if(x==f[x])return x;
	return f[x]=afind(f[x]);
}
int krus()
{
	sort(a+1,a+1+m,cmp);
	int ans=0;
	for(int i=1;i<=m;i++)
	{
		if(afind(a[i].from)==afind(a[i].to))continue;
		f[afind(a[i].from)]=afind(a[i].to);
		ans=a[i].data;
	}
	return ans;
}
int main()
{
	freopen("city.in","r",stdin);
	freopen("city.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)f[i]=i;
	for(int i=1;i<=m;i++)scanf("%d%d%d",&a[i].from,&a[i].to,&a[i].data);
	int ans=krus();
	printf("%d %d",n-1,ans);
	return 0;
}

T4:

根据数据范围 m2 下手。

1.当 m=1

k个最大字段和问题。

记录 dpi,j,k 为枚举到第 i 个数,已用掉 j 个子段,第 i 个数选择情况为 k 得到的最大值。

k=0 时,只能从上一层转移过来,上一层可选可不选,所以

dpi,j,k=max(dpi1,j,0,dpi1,j,1)

k=1 时,当选上一个数时,上个数可以与这个数合并为一个子序列,也可以这个数单独成一个子序列,上一个数不选那这个数单独成子序列。

dpi,j,k=ai+max(dpi1,j1,0,dpi1,j,1,dpi1,j1,1)

2.当 m=2

这个时候对于每一层的数,状态变多了起来,这里选择穷举所有状态。

设状态为 j

j=0 时,表示这一层左右两数都不选。

j=1 时,表示这一层只选左边的数。

j=2 时,表示这一层只选右边的数。

j=3 时,表示这一层选左右两边的数,且在同一个子矩阵。

j=4 时,表示这一层选左右两边的数,但不在同一个子矩阵。

那又可以列dp方程了,设 dpi,j,p 为第 i 层,状态为 j,且已选择 p 个子矩阵后得到的最大值。

当此层状态 j 与上层状态 t 相同时,可以之间从上一层转移过来,矩阵数不变。

j=t=0 时,dpi,j,p=dpi1,j,p

j=t=1 时,dpi,j,p=ai,0+dpi1,j,p

j=t=2 时,dpi,j,p=ai,1+dpi1,j,p

j=t=3 时,dpi,j,p=ai,0+ai,1+dpi1,j,p

j=t=4 时,dpi,j,p=ai,0+ai,1+dpi1,j,p


若此层状态与上层状态不同,那么矩阵数目会随之改变。


j=0,jt 时,此时矩阵数目与上一层一样

dpi,j,p=dpi1,t,p


j=1,jt 时,此时从上层转移下来,那么这将是下一个子矩阵的起点,方案数 +1

dpi,j,p=ai,0+dpi1,t,p1

特殊情况:当 t=4 时,那么上一层的左边是一个单独的字矩阵,可以选择与上一层进行拼接。

dpi,j,p=ai,0+dpi1,t,p


j=2,jt 时与第上种情况相同。

dpi,j,p=ai,1+dpi1,t,p1

特殊情况:当 t=4

dpi,j,p=ai,1+dpi1,t,p


j=3,jt 时,无论上一层情况如何,也不能与上一层进行衔接。所以

dpi,j,p=ai,0+ai,1+dpi1,t,p1


j=4,jt 时,若上一层为 12 那么就有一列可以衔接上一层,若无法衔接或不衔接方案数得加 2

dpi,j,p=ai,0+ai,1+dpi,t,p2

当特殊情况 t=1t=2

dpi,j,p=ai,0+ai,1+dpi,t,p2


注意:上述所有的特殊情况并不代表只从特殊情况转移,而是要与一般情况做比较取最优解。

然后求出 max(dpn,j,k) 即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=105;
const int K=15;
int n,m,k,a[2][N],dp[N][5][K],f[N][K][2];
int main()
{
	freopen("matrix.in","r",stdin);
	freopen("matrix.out","w",stdout);
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=n;i++)for(int j=0;j<m;j++)scanf("%d",&a[j][i]);
	if(m==1)
	{
		memset(f,-0x3f,sizeof(f));
		f[0][0][0]=0;
		for(int i=1;i<=n;i++)
		{
			for(int j=0;j<=k;j++)
			{
				f[i][j][0]=max(f[i-1][j][0],f[i-1][j][1]);
				if(j>0)f[i][j][1]=max(f[i-1][j-1][0]+a[0][i],max(f[i-1][j-1][1]+a[0][i],f[i-1][j][1]+a[0][i]));
			}
		}
		int ans=max(f[n][k][0],f[n][k][1]);
		printf("%d",ans);
		return 0;
	}
	memset(dp,-0x3f,sizeof(dp));
	dp[0][0][0]=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<5;j++)
		{
			for(int t=0;t<5;t++)
			{
				for(int p=0;p<=k;p++)
				{
					if(j!=t&&p>0)
					{
						if(j==1)dp[i][j][p]=max(dp[i][j][p],a[0][i]+dp[i-1][t][p-1]);
						if(j==1&&t==4)dp[i][j][p]=max(dp[i][j][p],a[0][i]+dp[i-1][t][p]);
						if(j==2)dp[i][j][p]=max(dp[i][j][p],a[1][i]+dp[i-1][t][p-1]);
						if(j==2&&t==4)dp[i][j][p]=max(dp[i][j][p],a[1][i]+dp[i-1][t][p]);
						if(j==3)dp[i][j][p]=max(dp[i][j][p],a[0][i]+a[1][i]+dp[i-1][t][p-1]);
						if(j==0)dp[i][j][p]=max(dp[i][j][p],dp[i-1][t][p]);
						if(j==4)
						{
							if(p>=2)dp[i][j][p]=max(dp[i][j][p],dp[i-1][t][p-2]+a[0][i]+a[1][i]);
							if(t==2||t==1)dp[i][j][p]=max(dp[i][j][p],dp[i-1][t][p-1]+a[0][i]+a[1][i]);
						}
					}
					if(j==t)
					{
						if(j==0)dp[i][j][p]=max(dp[i][j][p],dp[i-1][t][p]);
						if(j==1)dp[i][j][p]=max(dp[i][j][p],a[0][i]+dp[i-1][t][p]);
						if(j==2)dp[i][j][p]=max(dp[i][j][p],a[1][i]+dp[i-1][t][p]);
						if(j==3)dp[i][j][p]=max(dp[i][j][p],a[0][i]+a[1][i]+dp[i-1][t][p]);
						if(j==4)dp[i][j][p]=max(dp[i][j][p],a[0][i]+a[1][i]+dp[i-1][t][p]);
					}
				}
			}
		}
	}
	int ans=-1e9;
	for(int i=0;i<5;i++)ans=max(ans,dp[n][i][k]);
	printf("%d",ans);
	return 0;
}
/*
3 2 1
-1 2
2 -3
3 1
*/
posted @   Gmt丶Fu9ture  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示