2021/5/29模拟赛

T1

给一个长 L L L的书架,有黑书和白书,最左和最右都是黑书,黑书宽度可以是 1 1 1 H H H,白书必须是 1 1 1,问有几种排列方式。
一开始推不出样例,后来得知不用放满也算一中,然后先写了个暴力。

#include<bits/stdc++.h>
using namespace std;
#define int long long
int ans,h,l;bool flag;
void dfs(int n,int m)
{
	if(m>l)return;
	if(n%2==1){ans++;dfs(n+1,m+1);dfs(n+1,m+h);}
	else dfs(n+1,m+1);
}
signed main()
{
	scanf("%lld%lld",&l,&h);
	if(l%2==1)flag=1;if(h==l){cout<<((l+1)/2+1);return 0;}
	if(l<=10){dfs(1,1);dfs(1,h);printf("%lld",ans);return 0;}
	return 0;
}

就跟之前最早学 d f s dfs dfs的时候写的超级书架差不多。

T2

给出 n n n个命名, m m m组推导,每组输入 p p p q q q表示能由 p p p得到 q q q,输出第一行是至少把几个定为公理才能推到所有这些定理,第二行输出这些公理,第三行输出每个定理需要多少次推导能得到,如果是公理则只需要推导 0 0 0次。
一开始感觉有点像最近在搞的并查集,但是作业我没怎么写,不太会。
又有点像图论的东西,然而图论也是我的弱项。
并查集确实不会是最优的
确实应该是拓扑才对

再看T1

D P DP DP一个,二维,一维是长度,一维是颜色。
f [ i ] [ 白 ] = f [ i − 1 ] [ 黑 ] ; f[i][白]=f[i-1][黑]; f[i][]=f[i1][]
f [ i ] [ 黑 ] = f [ i − 1 ] [ 白 ] + f [ i − h ] [ 白 ] ; f[i][黑]=f[i-1][白]+f[i-h][白]; f[i][]=f[i1][]+f[ih][]
然后在初始化上调试了很久,最后还是保守一点,分段

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define N 1000010
int ans,h,l,j,p,f[N<<1][3];bool flag;
void dfs(int n,int m)
{
	if(m>l)return;
	if(n%2==1){ans++;dfs(n+1,m+1);dfs(n+1,m+h);}
	else dfs(n+1,m+1);
}
signed main()
{
	scanf("%lld%lld",&l,&h);
	if(h==l){cout<<((l+1)/2+1);return 0;}
	if(l<=10){dfs(1,1);dfs(1,h);printf("%lld",ans);return 0;}
	ans=0;f[N][1]=1;f[N+1][0]=1;f[N][0]=1;
	for(int i=2+N;i<=N+l;i++)
	{
		f[i][1]=f[i-1][0];
		f[i][0]=((f[i-1][1]+f[i-h][1])%998244353);
	}
	for(int i=1+N;i<=l+N;i++){ans=(ans+f[i][0])%998244353;}
	cout<<ans;
	return 0;
}

T3

n n n个乘客,每个有个上车时间和一个下车时间,有两种坐座位方式,一种是定票时,在上下车时间之间没人坐的位置可以坐。一种是上了车看见没位置就能坐(如果没理解错的话应该是这样)。
于是我写了个暴力

#include<bits/stdc++.h>
using namespace std;
#define N 100010
int ans1,ans2,n,flag1[N],flag2[N];
struct woshayebuhui{int s,t;}w[N];
bool mycmp(woshayebuhui x,woshayebuhui y){return ((x.s<y.s)||((x.s==y.s)&&(x.t<=y.t)));}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d%d",&w[i].s,&w[i].t);
	for(int i=1;i<=n;i++)
	{
		for(int j=w[i].s;j<=w[i].t;j++){flag1[j]++;}
		for(int j=w[i].s;j<w[i].t;j++){flag2[j]++;}
	}
	for(int i=1;i<=N;i++){ans1=max(ans1,flag1[i]);ans2=max(ans2,flag2[i]);}
	cout<<ans1<<' '<<ans2;
	return 0;
}

然后连第二个样例数据都过不去

整个模拟赛打得及其自闭,最近都没怎么敲代码,啥也不会。

听讲T1

一维 D P DP DP也可以写,把白色和黑色看成是一个整体即可。

订错T2

用个 b o o l bool bool数组存下哪些是可以被推导的,没被标记的视为公理,前两个问题就解决了。
至于推导多少次,显然这是一个有向无环图,所以一个拓扑排序就可以解决(我不太会)

#include<bits/stdc++.h>
using namespace std;
#define N 500010
int nxt[N],a[N],v[N],head[N],deg[N],n,m,p,q,k,cnt,tot;bool flag[N];
void add(int x,int y){v[++tot]=y;nxt[tot]=head[x];head[x]=tot;deg[y]++;}
void topsort()
{
	queue<int> q;
	for(int i=1;i<=n;i++)if(deg[i]==0){q.push(i);a[i]=0;}
	while(q.size())
	{
		int x=q.front();q.pop();
		for(int i=head[x];i;i=nxt[i])
		{
			int y=v[i];
			if(deg[y]==0) continue; 
			a[y]=min(a[y],a[x]+1);
			if(--deg[y]==0) q.push(y);
		}
	}
}
int main()
{
	scanf("%d%d",&n,&m);k=n;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&p,&q);add(p,q);
		if(flag[q]==0){flag[q]=1;k--;}
	}printf("%d\n",k);
	for(int i=1;i<=n;i++) a[i]=99999999;topsort();
	for(int i=1;i<=n;i++){if(flag[i]==0){printf("%d ",i);}}puts("");
	for(int i=1;i<=n;i++)printf("%d ",a[i]);
	return 0;
}

订错T3

题意理解错了,差分和线段树都可以写

#include<bits/stdc++.h>
using namespace std;
#define N 200010
int n,hh,c[N],s1[N],s2[N],ans1,ans2,l[N],r[N];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&l[i],&r[i]);
		hh=max(hh,r[i]);
		c[l[i]]++;c[r[i]]--;
		s1[l[i]]++;s2[r[i]]++;
	}
	for(int i=1;i<=hh;i++)
	{
		c[i]+=c[i-1];
		s1[i]+=s1[i-1];s2[i]+=s2[i-1];
		ans2=max(ans2,c[i]);
	}
	for(int i=1;i<=n;i++) ans1=max(ans1,s1[r[i]-1]-s2[l[i]]);
	printf("%d %d",ans1,ans2);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值