加载中…

返回上一页

CSP-S模拟19

下发文件

我发现写长了自己也不想再去看而且累赘,就写短点吧.

木棍

发现只有 5 种情况,22222、4222、442、2233、334. 那么贪心地每次选择最大的情况(就是把上面的反过来),减去即可.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 200001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x;if(x>9) write(x/10);putchar(x%10|'0'); }
ll t,n2,n3,n4,num,ans;
int main()
{
	t=read();while(t--)
	{
		ans=0;n2=read();n3=read();n4=read();
		// 5种情况,尽可能多用3和4
		// 1.3+3+4
		ans=num=min(n3>>1,n4);n3-=num<<1;n4-=num;
		// 2.2+4+4
		num=min(n2,n4>>1);ans+=num;n2-=num;n4-=num<<1;
		// 3.2+2+3+3
		num=min(n2>>1,n3>>1);ans+=num;n2-=num<<1;n3-=num<<1;
		// 4.2+2+2+4
		num=min(n2/3,n4);ans+=num;n2-=(num<<1)+num;n4-=num;
		// 5.2+2+2+2+2
		num=n2/5;ans+=num; write(ans);putn;
	}
	return 0;
}

dp[i][j] 表示已经考虑了左边前 i 个点和右边前 ai 个点,存在 j 条链的方案数(把单点看成链).

转移的时候考虑两种情况:

第一是新加进来点,乘一个组合数;
第二是是否合并为两条链,判断一下能否成环.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 5001
#define mod 998244353
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x;if(x>9) write(x/10);putchar(x%10|'0'); }
ll n,ans;
ll a[maxn],jc[maxn],ny[maxn],dp[maxn][maxn];
inline ll ksm(rll a,rll b) { rll ans=1;a%=mod; for(rll i=b;i;i>>=1) { if(i&1) ans=ans*a%mod; a=a*a%mod; } return ans; }
inline ll C(rll n,rll m) { if(n<m) return 0; return jc[n]*ny[m]%mod*ny[n-m]%mod; }
int main()
{
	jc[0]=1;for(rll i=1;i<maxn;i++) jc[i]=jc[i-1]*i%mod;
	ny[maxn-1]=ksm(jc[maxn-1],mod-2);for(rll i=maxn-2;~i;i--) ny[i]=ny[i+1]*(i+1)%mod;
	n=read();for(rll i=1;i<=n;i++) a[i]=read();sort(a+1,a+n+1); dp[0][0]=1;
	for(rll i=1;i<=n;i++)
	{
		for(rll j=0;j<=a[i];j++) for(rll k=0;k<=a[i]-a[i-1];k++) if(j-k>=0) (dp[i][j]+=dp[i-1][j-k]*C(a[i]-a[i-1],k)%mod)%=mod;
		(ans+=dp[i][1]-a[i]+mod)%=mod;
		for(rll j=0;j<=a[i];j++) (dp[i][j]+=dp[i][j+1]*j%mod*(j+1)%mod)%=mod;
	}
	write(ans*ksm(2,mod-2)%mod);
	return 0;
}

传令

考场上贪心假了只拿了 10.

考虑一棵子树,也是分两种情况:

对于能够完全覆盖的情况,就记录一下从这个点向外延伸出的距离(即接到命令的时间,设为 f);

对于有叶子没覆盖的情况,记录这个叶子的深度(设为 g),用子树外的点去覆盖它.

代码里有更详细的解释.

点击查看代码
#include<bits/stdc++.h>
#define ll int
#define rg register
#define rll rg ll
#define maxn 200001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x;if(x>9) write(x/10);putchar(x%10|'0'); }
ll n,k,l,r,mid,mx,rt,ans;
ll dp[maxn],g[maxn];
vector<ll> G[maxn];
inline ll dfs2(rll x,rll fa,rll mxd)
{
	// dp:每个点接到命令的时间
	// g:每个点到离它最远的未覆盖的子节点的距离
	rll ans=0; dp[x]=INT_MAX>>1;g[x]=-1;
	for(rll i=0;i<G[x].size();i++)
	{
		rll to=G[x][i];if(to==fa) continue;
		ans+=dfs2(to,x,mxd); dp[x]=min(dp[x],dp[to]+1);
		if(~g[to]) g[x]=max(g[x],g[to]+1);
	}
	if((~g[x])&&dp[x]+g[x]<=mxd) g[x]=-1;// 完全覆盖的情况
	if((fa&&G[x].size()==1)||dp[x]==mxd+1) g[x]=max(g[x],0);// 有叶子没覆盖的情况就记录这个叶子的深度,用子树外的点去覆盖它
	if(g[x]==mxd) ans++,dp[x]=0,g[x]=-1;// 建一个哨点
	return ans;
}
inline bool chk(rll x)
{
	return dfs2(1,0,x)+(bool)(~g[1])<=k;
}
int main()
{
	n=read();k=read();for(rll i=1,u,v;i<n;i++) G[u=read()].emplace_back((v=read())),G[v].emplace_back(u);
	l=1;r=(n>>1)+(n&1);while(l<=r)
	{
		mid=(l+r)>>1;
		if(chk(mid)) ans=mid,r=mid-1;else l=mid+1;
	}
	write(ans);
	return 0;
}

序列

暂时没弄明白先跳了,贺的这儿的.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 25001
#define mod 1000000007
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x;if(x>9) write(x/10);putchar(x%10|'0'); }
ll n,k,m,ans,l,r;
ll a[maxn],f[maxn][501],g[maxn][501];
bool fl[maxn];
inline ll ksm(rll a,rll b) { rll ans=1;a%=mod; for(rll i=b;i;i>>=1) { if(i&1) ans=ans*a%mod; a=a*a%mod; } return ans; }
inline bool spj1()
{
	for(rll i=1;i<=m-k+1;i++)
	{
		memset(fl,0,sizeof(fl));rg bool flag=0;
		for(rll j=i;j<=i+k-1;j++) if(fl[a[j]]) { flag=1; break; }
		else fl[a[j]]=1; if(!flag) return 1;
	}
	return 0;
}
int main()
{
	n=read();k=read();m=read(); ans=n-m+1; for(rll i=1;i<=m;i++) a[i]=read(); l=1;r=m;
	for(rll i=1;i<=n-m;i++) ans=ans*k%mod; if(spj1()) { write(ans); return 0; }
	memset(fl,0,sizeof(fl));for(rll i=1;i<=m;i++) if(fl[a[i]]) { r=i-1;break; }
	else fl[a[i]]=1;
	memset(fl,0,sizeof(fl));for(rll i=m;i;i--) if(fl[a[i]]) { l=m-i;break; }
	else fl[a[i]]=1;
	if(l==1&&r==m)
	{
		f[0][0]=1;
		for(rll i=1;i<=n;i++)
		{
			for(rll j=1;j<k;j++)
			{
				f[i][j]=((f[i-1][j-1]-f[i-1][j]+mod)*(k-j+1)+f[i-1][j])%mod;
				g[i][j]=((g[i-1][j-1]-g[i-1][j]+mod)*(k-j+1)+g[i-1][j])%mod;
				if(j>=m)g[i][j]=(g[i][j]+f[i][j])%mod;
			}
			for(rll j=k-1;~j;j--)f[i][j]=(f[i][j]+f[i][j+1])%mod,g[i][j]=(g[i][j]+g[i][j+1])%mod;
		}
		rll t=g[n][0];for(rll i=k;i>k-m;i--) t=t*ksm(i,mod-2)%mod; write((ans-t+mod)%mod);
	}
	else
	{
		for(rll i=0;i<=r;i++) f[0][i]=1; for(rll i=0;i<=l;i++) g[0][i]=1;
		for(rll i=1;i<=n;i++)
		{
			for(rll j=1;j<k;j++) f[i][j]=((f[i-1][j-1]-f[i-1][j]+mod)*(k-j+1)+f[i-1][j])%mod,g[i][j]=((g[i-1][j-1]-g[i-1][j]+mod)*(k-j+1)+g[i-1][j])%mod;
			for(rll j=k-1;~j;j--) f[i][j]=(f[i][j]+f[i][j+1])%mod,g[i][j]=(g[i][j]+g[i][j+1])%mod;
		}
		rll t=0; for(rll i=0;i<=n-m;i++)t=(t+f[i][0]*g[n-m-i][0])%mod; write((ans-t+mod)%mod);
	}
	return 0;
}
posted @ 2022-10-16 16:29  1Liu  阅读(53)  评论(1)    收藏  举报