2021.07.15【普及组】模拟赛C组

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王 * 轩 提供的代码!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值