2021.07.15【普及组】模拟赛C组
前言
大水题(只是没交上)系统问题TAT
矩阵
題目大意
给出A,B,C三个01矩阵,问A*B是否等于C.
解析
暴力(80分)直接搜,把每行每列的1累加求(TLE)
正解 随机数(蒟蒻只会这个方法不会优化)
随机生成N个1维数组,依次相乘,比较(不用累加)
代码
#include<cstdio>
#include<ctime>
#include<cstdlib>
#include<cstring>
using namespace std;
int n,t,flag;
int x[100005],y[100005],z[100005],f[100005];
int a[1005][1005],b[1005][1005],c[1005][1005];
int main()
{
srand(time(NULL));
scanf("%d",&t);
while(t--)
{
char ch;
scanf("%d\n",&n);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%c",&ch);
a[i][j]=ch-48;
}
scanf("\n");
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%c",&ch);
b[i][j]=ch-48;
}
scanf("\n");
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%c",&ch);
c[i][j]=ch-48;
}
scanf("\n");
}
flag=0;
for(int i=1;i<=10;i++)
{
for(int i=1;i<=n;i++)
f[i]=rand()%2+0;
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
memset(z,0,sizeof(z));
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
y[j]=y[j]^(b[j][k]&f[k]);
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
x[j]=x[j]^(a[j][k]&y[k]);
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
z[j]=z[j]^(c[j][k]&f[k]);
for(int j=1;j<=n;j++)
if(x[j]!=z[j])
{
flag=1;
printf("NO\n");
break;
}
if(flag)break;
}
if(!flag)printf("YES\n");
}
return 0;
}
三角形
題目大意
给出N个等腰直角三角形的顶点坐标(x,y),其中y>=0;要你求出这N个等腰直角三角形的面积和(注意,重叠部分只算一次)。
解析
排序,一堆判断有没有重叠,相交(详见代码)
代码
#include<bits/stdc++.h>
#define ll long long
#define ld long double
using namespace std;
const int M=1e5+5,MAX=1e9,MIN=-1e9;
struct sjx
{
ld l,r,x,y;
};
sjx t[M*2],tmp;
ld ans1;
int n;
void qsort(int l,int r)
{
int i=l,j=r;
ld mid=t[(l+r)/2].l;
while(i<=j)
{
while(t[i].l<mid)i++;
while(t[j].l>mid)j--;
if(i<=j)
{
tmp=t[i];t[i]=t[j];t[j]=tmp;
i++;j--;
}
}
if(i<r)qsort(i,r);
if(j>l)qsort(l,j);
}
ld ques(ld x,ld y)
{
return (ld)((y-x)*(y-x)*0.25);
}
int main()
{
int s;
scanf("%d",&s);
while(s--)
{
ans1=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%Lf%Lf",&t[i].x,&t[i].y);
t[i].l=t[i].x-t[i].y;t[i].r=t[i].x+t[i].y;
}
qsort(1,n);
ans1=ques(t[1].l,t[1].r);
for(int i=2;i<=n;i++)
{
if(t[i].l>=t[i-1].r)ans1=ans1+ques(t[i].l,t[i].r);
else if(t[i].r<=t[i-1].r)t[i]=t[i-1];
else ans1=ans1+ques(t[i].l,t[i].r)-ques(t[i].l,t[i-1].r);
}
printf("%.2Lf\n",ans1);
}
return 0;
}
字符串的展开
題目大意
在初赛普及组的“阅读程序写结果”的问题中,我们曾给出一个字符串展开的例子:如果在输入的字符串中,含有类似于“d-h”或“4-8”的子串,我们就把它当作一种简写,输出时,用连续递增的字母或数字串替代其中的减号,即,将上面两个子串分别输出为“defgh”和“45678”。在本题中,我们通过增加一些参数的设置,使字符串的展开更为灵活。具体约定如下:
(1)遇到下面的情况需要做字符串的展开:在输入的字符串中,出现了减号“-”,减号两侧同为小写字母或同为数字,且按照ASCII码的顺序,减号右边的字符严格大于左边的字符。
(2)参数p1:展开方式。p1=1时,对于字母子串,填充小写字母;p1=2时,对于字母子串,填充大写字母。这两种情况下数字子串的填充方式相同。p1=3时,不论是字母子串还是数字子串,都用与要填充的字母个数相同的星号“*”来填充。
(3)参数p2:填充字符的重复个数。p2=k表示同一个字符要连续填充k个。例如,当p2=3时,子串“d-h”应扩展为“deeefffgggh”。减号两侧的字符不变。
(4)参数p3:是否改为逆序:p3=1表示维持原有顺序,p3=2表示采用逆序输出,注意这时仍然不包括减号两端的字符。例如当p1=1、p2=2、p3=2时,子串“d-h”应扩展为“dggffeeh”。
(5)如果减号右边的字符恰好是左边字符的后继,只删除中间的减号,例如:“d-e”应输出为“de”,“3-4”应输出为“34”。如果减号右边的字符按照ASCII码的顺序小于或等于左边字符,输出时,要保留中间的减号,例如:“d-d”应输出为“d-d”,“3-1”应输出为“3-1”。
解析
选择嵌套(没什么好讲的,详见代码)
代码
#include<bits/stdc++.h>
using namespace std;
int p1,p2,p3,n;
char c[200];
int main()
{
freopen("expand.in","r",stdin);
freopen("expand.out","w",stdout);
scanf("%d%d%d",&p1,&p2,&p3);
scanf("%s",c+1);
n=strlen(c+1);
for(int i=1;i<=n;i++)
{
if(c[i]=='-'&&c[i-1]<c[i+1])
{
if((c[i-1]>='a'&&c[i-1]<='z'&&c[i+1]>='a'&&c[i+1]<='z'))
{
if(p3==1)
{
for(char j=c[i-1]+1;j<c[i+1];j++)
for(int k=1;k<=p2;k++)
{
if(p1==1)printf("%c",j);
if(p1==2)printf("%c",j-32);
if(p1==3)printf("*");
}
}
else
{
for(char j=c[i+1]-1;j>c[i-1];j--)
for(int k=1;k<=p2;k++)
{
if(p1==1)printf("%c",j);
if(p1==2)printf("%c",j-32);
if(p1==3)printf("*");
}
}
}
else if(c[i-1]>='0'&&c[i-1]<='9'&&c[i+1]>='0'&&c[i+1]<='9')
{
if(p3==1)
{
for(char j=c[i-1]+1;j<c[i+1];j++)
for(int k=1;k<=p2;k++)
if(p1==3)printf("*");
else printf("%c",j);
}
else
{
for(char j=c[i+1]-1;j>c[i-1];j--)
for(int k=1;k<=p2;k++)
if(p1==3)printf("*");
else printf("%c",j);
}
}
else printf("%c",c[i]);
}
else printf("%c",c[i]);
}
return 0;
}
小树
題目大意
给出一个树,树的边上有权值,现在要你求出一个满足下面三个要求的节点集合。第一,根节点不在集合S中。第二,集合中任何两个节点仅有一个公共祖先,即根节点。第三,对集合中每个节点都要有两个值,wi表示到这个节点的路径上所有的边权值总和,di表示到这个节点的路径所包含的边数,现在要求sigma(wi)/sigma(di)的最大值。
解析
递归(没那么复杂)
找到最大值输出即可
代码
#include<bits/stdc++.h>
int n,T,mp[1001][1001];
bool bz[1001];
double mx;
inline void dfs(int x,double w,double d)
{
if(d!=0) if(w/d>mx) mx=w/d;
for(int i=0;i<n;++i)
{
if(!bz[i]&&mp[x][i])
{
bz[i]=1;
dfs(i,w+mp[x][i],d+1);
bz[i]=0;
}
}
}
int main()
{
scanf("%d",&T);
while(T--)
{
mx=0;
scanf("%d",&n);
if(n==1)
{
printf("0.00\n");
continue;
}
memset(mp,0,sizeof(mp));
for(int i=1;i<n;++i)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
mp[x][y]=z;mp[y][x]=z;
}
bz[0]=1;
dfs(0,0,0);
printf("%.2lf\n",mx);
}
}
后记
一堆水题(没什么好讲的)系统问题我也没话说。
感谢 2021王 * 轩 提供的代码!!