20240219比赛总结

T1 素数

https://gxyzoj.com/d/hzoj/p/3598

先预处理出32767以下的质数,再用双指针求解

#include<cstdio>
using namespace std;
int p[32767],m,n,ans,x;
bool vis[32768];
void prime()
{
	for(int i=2;i<=32767;i++)
	{
		if(!vis[i]) p[++m]=i;
		for(int j=1;i*p[j]<=32767;j++)
		{
			vis[i*p[j]]=1;
			if(i%p[j]==0) break;
		}
	}
}
int main()
{
	scanf("%d",&n);
	prime();
	while(n)
	{
		ans=x=0;
		for(int i=1,j=0;i<=m;i++)
		{
		//	printf("%d ",p[i]);
			x-=p[i-1];
			while(x+p[j+1]<=n)
			{
				j++;
				x+=p[j];
			}
			if(x==n) ans++;
		}
		printf("%d\n",ans);
		scanf("%d",&n);
	}
	return 0;
}

T2 晨练

https://gxyzoj.com/d/hzoj/p/3599

\(dp_{i,j,0/1}\)表示第i分钟疲劳度为j,不跑/跑的最大距离,易得转移方程:

\[\begin{cases}dp_{i,j,0}=max(dp_{i-1,j+1,0},dp_{i-1,j+1,1}),0<j<m\\dp_{i,j,1}=dp_{i-1,j-1,1}+d_i,1<j\\ dp_{i,1,1}=dp_{i-1,0,0}+d_i\\ dp_{i,0,0}=max(dp_{i-1,0,0},dp_{i-1,1,1},dp_{i-1,1,0})\end{cases} \]

代码:

#include<cstdio>
#include<algorithm>
using namespace std;
int n,d[10005],dp[10005][505][2],m;
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&d[i]);
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<=min(i,m);j++)
		{
			dp[i][j][0]=max(dp[i-1][j+1][0],dp[i-1][j+1][1]);
			dp[i][j][1]=dp[i-1][j-1][1]+d[i];
			if(j==0) dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][0]),dp[i][j][1]=-1e9;
			if(j==1) dp[i][j][1]=dp[i-1][0][0]+d[i];
			if(j==min(i,m)) dp[i][j][0]=-1e9;
		//	printf("%d %d %d %d\n",i,j,dp[i][j][0],dp[i][j][1]);
		}
	}
	printf("%d",dp[n][0][0]);
	return 0;
}

T3 奇怪的桌子

https://gxyzoj.com/d/hzoj/p/3600

根据样例解释,容易发现,若第i列与第j列满足\(i\ \bmod n=j\ \bmod n\),则第i列与第j列的点数相同,所以只用枚举前n列即可,由此可想到dp

\(dp_{i,j}\)表示目前在第i列,用了j个点,所以转移方程为:

\[dp_{i,j}=\sum_{p=0}^{n} dp_{i-1,j-p}\times(C_n^p)^{\lfloor\frac{m}{n}\rfloor+[i\le m \bmod n]} \]

代码:

#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
int p=1e9+7;
ll n,m,k,f[105][10005],fac[105],inv[105],p1[2][105];
ll qpow(ll x,ll y)
{
	ll res=1;
	while(y)
	{
		if(y&1) res=res*x%p;
		x=x*x%p;
		y>>=1;
	}
	return res;
}
ll C(ll n,ll m)
{
	if(n==0||m==0||n<m) return 1;
	return fac[n]*inv[m]%p*inv[n-m]%p;
}
int main()
{
	scanf("%lld%lld%lld",&n,&m,&k);
	fac[0]=1;
	for(int i=1;i<=n;i++)
	{
		fac[i]=fac[i-1]*i%p;
	}
	inv[n]=qpow(fac[n],p-2);
	for(int i=n-1;i>=0;i--)
	{
		inv[i]=inv[i+1]*(i+1)%p;
	}
	for(int i=0;i<=n;i++)
	{
		p1[0][i]=qpow(C(n,i),m/n);
		p1[1][i]=p1[0][i]*C(n,i)%p;
	//	printf("%d %d\n",p1[0][i],p1[1][i]);
	}
	f[0][0]=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=max(0*1ll,k-n*(n-i));j<=min(k,n*i);j++)
		{
			for(int l=0;l<=min(n,j*1ll);l++)
			{
				if(i>m%n)
				f[i][j]=(f[i][j]+f[i-1][j-l]*p1[0][l]%p)%p;
				else
				f[i][j]=(f[i][j]+f[i-1][j-l]*p1[1][l]%p)%p;
			}
		//	printf("%d %d %lld\n",i,j,f[i][j]);
		}
	//	printf("\n");
	}
	printf("%lld",f[n][k]%p);
	return 0;
}

T4 学校

https://gxyzoj.com/d/hzoj/p/3601

先求出最短路,再将处于最短路上的边建新图,在新图上求割边,如果边(u,v)是割边,则输出No,否则输出Yes

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,h1[40005],edgenum,head[40005],s,t;
struct edge{
	int to,val,id,nxt;
}e[400005],e1[400005];
void add(int u,int v,int w,int id)
{
	e1[++edgenum].nxt=h1[u];
	e1[edgenum].to=v;
	e1[edgenum].id=id;
	e1[edgenum].val=w;
	h1[u]=edgenum;
}
void add_edge(int u,int v,int w,int id)
{
	e[++edgenum].nxt=head[u];
	e[edgenum].to=v;
	e[edgenum].id=id;
	e[edgenum].val=w;
	head[u]=edgenum;
}
int dis[40004];
priority_queue<pair<int,int> >q;
void dijkstra(int s)
{
	q.push(make_pair(0,s));
	for(int i=1;i<=n;i++) dis[i]=2e9;
	dis[s]=0;
	while(!q.empty())
	{
		int w=q.top().first*(-1),u=q.top().second;
		q.pop();
		if(w!=dis[u]) continue;
		for(int i=h1[u];i;i=e1[i].nxt)
		{
			int v=e1[i].to;
			if(dis[u]+e1[i].val<dis[v])
			{
				dis[v]=dis[u]+e1[i].val;
				q.push(make_pair(-dis[v],v));
			}
		}
	}
}
bool vis[40005],bri[400004],e_vis[400005];
void dfs(int u)
{
	if(vis[u]||u==s) return;
	vis[u]=1;
//	printf("%d %d\n",u,h1[u]);
	for(int i=h1[u];i;i=e1[i].nxt)
	{
		if(e_vis[i]) continue;
		int v=e1[i].to;
//		printf("%d %d %d\n",i,u,v);
		if(e1[i].val+dis[v]==dis[u])
		{
		//	printf(" %d %d %d\n",i,u,v);
			add_edge(u,v,e1[i].val,e1[i].id);
		//	printf("%d %d %d\n",edgenum,u,v);
			add_edge(v,u,e1[i].val,e1[i].id);
		//	printf("%d %d %d\n",edgenum,v,u);
			e_vis[i]=e_vis[i^1]=1;
			dfs(v);
		}
	}
}
int dfn[40005],low[40005],idx;
void tarjan(int i,int in_edge)
{
	dfn[i]=low[i]=++idx;
	for(int u=head[i];u;u=e[u].nxt)
	{
		int j=e[u].to;
		if(!dfn[j])
		{
			tarjan(j,u);
			low[i]=min(low[i],low[j]);
			if(low[j]>dfn[i])
			{
				bri[e[u].id]=1;
			}
		}
		else if(u!=(in_edge^1))
		{
			low[i]=min(low[i],dfn[j]);
		}
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	scanf("%d%d",&s,&t);
	edgenum=1;
	for(int i=1;i<=m;i++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w,i);
	//	printf("%d ",edgenum);
		add(v,u,w,i);
	//	printf("%d\n",edgenum);
	}
	dijkstra(s);
	edgenum=1;
	dfs(t);
	tarjan(s,0);
	int q;
	scanf("%d",&q);
	while(q--)
	{
		int x;
		scanf("%d",&x);
		if(bri[x]) printf("No\n");
		else printf("Yes\n");
	}
	return 0;
}
posted @ 2024-02-23 15:06  wangsiqi2010916  阅读(19)  评论(0编辑  收藏  举报