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[i−1][黑];
f
[
i
]
[
黑
]
=
f
[
i
−
1
]
[
白
]
+
f
[
i
−
h
]
[
白
]
;
f[i][黑]=f[i-1][白]+f[i-h][白];
f[i][黑]=f[i−1][白]+f[i−h][白];
然后在初始化上调试了很久,最后还是保守一点,分段
#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;
}