20240221比赛总结

T1 排序

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

根据代数的内容,容易得到:若\(a\ge b\ge c\ge d\),则有
\(ab-cd\ge ac-bd\ge ad-bc\)

所以,只需要前2n个一大一小搭配,后2n个两两搭配,即为答案

代码:

#include<cstdio>
#include<algorithm>
#define ull unsigned long long
using namespace std;
int n,a[400005];
ull ans;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n*4;i++)
	{
		scanf("%d",&a[i]);
	}
	sort(a+1,a+4*n+1);
	for(int i=1;i<=n;i++)
	{
		long long x=1ll*a[2*n+2*i-1]*a[2*n+2*i]-1ll*a[i]*a[2*n-i+1];
		ans=ans+x;
	}
	printf("%llu",ans);
	return 0;
}

T2 牛吃草

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

考虑二分答案,因为size具有单调性,所以可以二分size的最小值,check函数由dp实现,设\(f_i\)表示满足最小覆盖大小的情况下,前i个点的最大覆盖数,所以,可得转移方程:

\[f_i=\max_{i-w_i\le j\le i-size}(f_{i-1},f_j+i-j) \]

因为题目中w[i]的限制条件,i不变,所以可以用单调队列维护\(f_j-j\)的最大值

代码:

#include<cstdio>
#include<algorithm>
using namespace std;
int n,a[500005],f[500005],q[500005],head,tail,pos,ans;
bool check(int size)
{
	head=1,tail=1;
	for(int i=0;i<=n;i++)
	{
		f[i]=q[i]=0;
	}
	q[tail]=0;
//	printf("\n%d\n",size);
	for(int i=1;i<=n;i++)
	{
		f[i]=f[i-1];
		if(i-size>=0)
		{
			int x=i-size;
			while(head<=tail&&f[q[tail]]-q[tail]<=f[x]-x) tail--;
			q[++tail]=x;
		}
		while(head<=tail&&q[head]<i-a[i]) head++;
		if(a[i]>=size)
		{
			if(head<=tail)
			f[i]=max(f[i-1],i+f[q[head]]-q[head]);
		}
	//	printf("%d ",f[i]);
	}
//	if(size==250000) printf("%d\n",f[n]);
	if(f[n]>=pos) return 1;
	return 0;
}
int main()
{
//	freopen("testcase20.in","r",stdin);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		if(a[i]>i) a[i]=i;
	}
	int s;
	scanf("%d",&s);
	pos=(n*s+99)/100;
	int l=1,r=n;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(check(mid))
		{
			ans=max(ans,mid);
			l=mid+1;
		}
		else
		{
			r=mid-1;
		}
	}
//	check(250000);
	printf("%d",ans);
	return 0;
}

T3 树上的宝藏

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

很像暑假的一道题: P6419

换根DP,我们假设1为根,做树形dp,设\(dp_{u,0/1}\)表示u不选/选时u子树内的方案数,易得转移方程:

\[\begin{cases}dp_{u,0}=\prod_{v\in son(u)}(dp_{v,0}+dp_{v,1})\\ dp_{u,1}=\prod_{v\in son(u)}dp_{v,0}\end{cases} \]

因为要换根,所以还要记录子树外的方案数,设\(f_{u,0/1}\)表示u不选/选时u子树外的方案数,转移方程为:

\[\begin{cases}f_{u,0} = dp_{fa,0} \div (dp_{u,0}+dp_{u,1}) \times f_{fa,0} + dp_{fa,1} \div dp_{u,0} \times f_{fa,1} \\ f_{u,1} = dp_{fa,0} \div (dp_{u,0}+dp_{u,1}) \times f_{fa,0} \end{cases} \]

接着考虑统计答案,在dfs的同时,统计深度,对于每一条边,记深度小的节点为u,深度大的为v,所以有三种情况:

只选u:

res=dp[u][1]*f[u][1]%p;

u,v都选:

res=f[u][1]*dp[u][1]%p;
res=res*qpow(dp[v][0]%p,p-2)%p*dp[v][1]%p

只选v:

res=dp[u][0]*f[u][0]%p;
res=res*qpow((dp[v][0]+dp[v][1])%p,p-2)%p*dp[v][1]%p;

注意取模!注意取模!注意取模!

(100->30)

完整代码(考后改的):

#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int p=998244353;
int n,edgenum,head[300005],x[300005],y[300006];
struct edge{
	int to,nxt;
}e[600005];
void add(int u,int v)
{
	e[++edgenum].nxt=head[u];
	e[edgenum].to=v;
	head[u]=edgenum;
}
ll f1[300005][2],f2[300005][2],f[300005];
int dep[300005];
ll qpow(ll x,int y)
{
	ll res=1;
	while(y)
	{
		if(y&1) res=res*x%p;
		x=x*x%p;
		y>>=1;
	}
	return res;
}
void dfs(int u,int fa)
{
	dep[u]=dep[fa]+1;
	f[u]=fa;
	f1[u][0]=f1[u][1]=1;
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		dfs(v,u);
	//	printf("%d %d\n",u,v);
		f1[u][1]=f1[u][1]*f1[v][0]%p;
		f1[u][0]=f1[u][0]*(f1[v][0]+f1[v][1])%p;
	}
}
void dfs1(int u,int fa)
{
	ll s=f2[u][0],t=f2[u][1];
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		s=s*(f1[v][0]+f1[v][1])%p;
		t=t*f1[v][0]%p;
	}
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		ll s1=s*qpow((f1[v][0]+f1[v][1])%p,p-2)%p,t1=t*qpow(f1[v][0],p-2)%p;
		f2[v][0]=(s1+t1)%p;
		f2[v][1]=s1;
		dfs1(v,u);
	}
}
ll query1(int u,int v)
{
	ll res=f2[u][1]*f1[u][1]%p;
	return res%p;
}
ll query2(int u,int v)
{
	ll res=f2[u][1]*f1[u][1]%p;
	res=res*qpow(f1[v][0]%p,p-2)%p*f1[v][1]%p;
	return res%p;
}
ll query3(int u,int v)
{
	ll res=f2[u][0]*f1[u][0]%p;
	res=res*qpow((f1[v][0]+f1[v][1])%p,p-2)%p*f1[v][1]%p;
	return res%p;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&x[i],&y[i]);
		add(x[i],y[i]);
		add(y[i],x[i]);
	}
	dfs(1,0);
	f2[1][1]=f2[1][0]=1;
	dfs1(1,0);
	for(int i=1;i<n;i++)
	{
		if(dep[x[i]]>dep[y[i]]) swap(x[i],y[i]);
		printf("%lld\n",(query1(x[i],y[i])+query2(x[i],y[i])+query3(x[i],y[i]))%p);
	}
	return 0;
}

T4 MEX

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

有人会吗,蒟蒻求教T_T

posted @ 2024-02-23 14:38  wangsiqi2010916  阅读(11)  评论(0编辑  收藏  举报