2021-07-20【普及组】模拟赛C组 总结
作者:互联网
2021.07.20【普及组】模拟赛C组 总结
文章目录
一.说在前面
今天的比赛,感觉没有进入状态,所以… 现在进入今天的题解 + 总结!!
二.题解
T 1: 排座椅(seat)
1.题目大意
上课的时候总有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情。不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下来之后,只有有限的D对同学上课时会交头接耳。同学们在教室中坐成了M行N列,坐在第i行第j列的同学的位置是(i,j),为了方便同学们进出,在教室中设置了K条横向的通道,L条纵向的通道。于是,聪明的小雪想到了一个办法,或许可以减少上课时学生交头接耳的问题:她打算重新摆放桌椅,改变同学们桌椅间通道的位置,因为如果一条通道隔开了两个会交头接耳的同学,那么他们就不会交头接耳了。
请你帮忙给小雪编写一个程序,给出最好的通道划分方案。在该方案下,上课时交头接耳的学生对数最少。
2.思路
贪心 + 排序,开大一点的数组,要排两次序,一次求出行的前 K 个和列的前 L 个,第二次给他们排个序。
3.实现
#include<bits/stdc++.h>
using namespace std;
int m,n,k,l,d;
int hang[10010],lie[10010];
int bzh[10010],bzl[10010];
void pl(int i,int j,int a[],int bz[])
{
int le=i,ri=j,mid=a[(i+j+1)/2];
while(i<=j)
{
while(a[i]>mid)
i++;
while(a[j]<mid)
j--;
if(i<=j)
{
swap(a[i],a[j]);
swap(bz[i],bz[j]);
i++; j--;
}
}
if(le<j)
pl(le,j,a,bz);
if(i<ri)
pl(i,ri,a,bz);
}
void ph(int i,int j,int a[])
{
int le=i,ri=j,mid=a[(i+j+1)/2];
while(i<=j)
{
while(a[i]<mid)
i++;
while(a[j]>mid)
j--;
if(i<=j)
{
swap(a[i],a[j]);
i++; j--;
}
}
if(le<j)
ph(le,j,a);
if(i<ri)
ph(i,ri,a);
}
int main()
{
scanf("%d%d%d%d%d",&m,&n,&k,&l,&d);
for(int i=1;i<=d;i++)
{
int x,y,p,q;
scanf("%d%d%d%d",&x,&y,&p,&q);
if(x==p)
{
lie[min(y,q)]++;
bzl[min(y,q)]=min(y,q);
}
else if(y==q)
{
hang[min(x,p)]++;
bzh[min(x,p)]=min(x,p);
}
}
pl(1,d*4,lie,bzl);
pl(1,d*4,hang,bzh);
ph(1,k,bzh);
ph(1,l,bzl);
for(int i=1;i<=k;i++)
if(bzh>0)
cout<<bzh[i]<<" ";
printf("\n");
for(int i=1;i<=l;i++)
if(bzl>0)
cout<<bzl[i]<<" ";
return 0;
}
T 2: 传球游戏(ball)
1.题目大意
上体育课的时候,小蛮的老师经常带着同学们一起做游戏。这次,老师带着同学们一起做传球游戏。
游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球,每个同学可以把球传给自己左右的两个同学中的一个(左右任意),当老师再次吹哨子时,传球停止,此时,拿着球没传出去的那个同学就是败者,要给大家表演一个节目。
聪明的小蛮提出一个有趣的问题:有多少种不同的传球方法可以使得从小蛮手里开始传的球,传了m次以后,又回到小蛮手里。两种传球的方法被视作不同的方法,当且仅当这两种方法中,接到球的同学按接球顺序组成的序列是不同的。比如有3个同学1号、2号、3号,并假设小蛮为1号,球传了3次回到小蛮手里的方式有1->2->3->1和1->3->2->1,共2种。
求符合题意的方法数。
2.思路
DP!!状态转移方程为(设 f [ i , j ] 为第 j 步第 i 个人选择方案数):
f
i
,
j
=
f
i
+
1
,
j
−
1
+
f
i
−
1
,
j
−
1
f_{i,j}=f_{i+1,j-1} + f_{i-1,j-1}
fi,j=fi+1,j−1+fi−1,j−1
(听说可以用滚动数组)
3.实现
#include<bits/stdc++.h>
using namespace std;
int n,m;
int f[50][50];
int main()
{
scanf("%d%d",&n,&m);
f[1][n]=f[1][2]=f[1][0]=1;
for(int i=2;i<=m;++i)
for(int j=1;j<=n;++j)
{
f[i][j]=f[i-1][j-1]+f[i-1][j+1];
f[i][0]=f[i][n];
f[i][n+1]=f[i][1];
}
printf("%d",f[m][1]);
return 0;
}
记得初始化数组哦
T 3: 立体图(drawing)
1.题目大意
给你一个二维的图(m * n),图上有一些数表示在三维里这一数列叠着多少个方块,然后输出。
2.思路
一开始看到这题,就赶紧跳过,因为有点难,听了题解后明白原来可以覆盖!但,这是方块?
3.实现
这就是模拟,康康主程序:
for(register int i=1;i<=n;i++)
for(register int j=1;j<=m;j++)
for(register int k=1;k<=a[i][j];k++)
{
int x=(n-i)*2+3*k-2,y=(n-i)*2+4*j-3;
x=mm-x+1;
for(register int l=x,ll=0;l>=x-5&&ll<=5;l--,ll++)
for(register int p=y,pp=0;p<=y+6&&pp<=6;p++,pp++)
if(b[ll][pp]!='.') c[l][p]=b[ll][pp];
}
T 4: 间谍派遣
1.题目大意
请找出间谍完成任务的最小花费,即组织会面和派遣间谍的费用之和。(因为他们要去**拯救世界**)
2.思路
最小生成树!!把他们的会面连在一起,再开一个超级汇点,表示他们参加任务所给的 money 。
3.实现
因为这题的质量过于优质,所以就不写代码了。
T 5: seek
1.题目大意
找出一个字符串中的相同前缀与后缀。
2.思路
K M P 裸题!!
3.实现
#include<bits/stdc++.h>
using namespace std;
char s[400010];
int next[400010],tot=1;
int ans[400010];
int main()
{
scanf("%s",s+1);
int len=strlen(s+1);
int j=0;
for(int i=1;i<=len;++i)
{
while(j>0 && s[i+1]!=s[j+1])
j=next[j];
if(s[i+1]==s[j+1])
j++;
next[i+1]=j;
}
j=len;
ans[1]=len;
while(next[j])
{
ans[++tot]=next[j];
j=next[j];
}
for(int i=tot;i>=1;i--)
if(ans[i]>0)
printf("%d ",ans[i]);
return 0;
}
三.后记
祝大家早日AK!
标签:同学,20,07,int,d%,++,while,2021,大意 来源: https://blog.csdn.net/YJH20200901/article/details/118944167