【CSDN竞赛】第七期解题报告

18 篇文章 0 订阅
17 篇文章 0 订阅

这应该是站内相对详细的解题报告吧。
转载思路请@本人。

感想

关于自己

这一次感觉题目变水了(对比第五期来说,只是个人感觉)
其实本来想着可能人均满分来划水的,没想到emm……排名:2
上一期由于和CSP冲突,所以错过了比赛
CSP的比赛时间恰好把第六期比赛时间包住了QAQ
然后捏,由于自己在第二题思考的时间过长,导致错失第一,哎
第八期要开始了,希望自己能考得好一些吧
毕竟就在CSP复赛后一天( R P + + RP++ RP++

关于平台

这一次倒是没有出什么错误了
觉得限制入场时间做得很好,不过建议一点:
排名最后出!
因为有些人可能根据排名来控制自己的分数和时间(这很让我无语。。)
这次也没有硬性要求发在特殊地方了,只要发了博客就行了
顺便提一句:每日一题上的难度偏差太大了吧,困难题随便切,简单题卡死不会
建议工作人员能抽出时间好好整理一下难度标签

第一题 奇偶排序(难度:签到)

题目描述

给定一个存放整数的数组,重新排列数组使得数组左边为奇数,右边为偶数。

100分做法

其实思路非常简单,
先输出奇数,后输出偶数就行啦(根本没有什么排序)。
C + + C++ C++代码如下:

#include<cstdio>
int a[100005];
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)if(a[i]%2!=0)printf("%d ",a[i]);
	for(int i=1;i<=n;i++)if(a[i]%2==0)printf("%d ",a[i]);
}

第二题 小艺照镜子(难度:入门)

题目描述

求已知字符串的最长回文子串。

100分做法1

看到回文串,我们可以想到马拉车、字符串哈希……随便选一种来做就切了。

100分做法2

发现 n ≤ 10000 n\leq10000 n10000
然后,暴力就可以过!
于是我们枚举中间点,然后暴力往两边拓展,
拓展到两边都不相同后停止,计算答案,
最后输出最大值即可。
注意!

  1. 奇数串和偶数串分开处理;
  2. C + + C++ C++读入很EX,我是用 g e t c h a r ( ) getchar() getchar()读入的, s c a n f scanf scanf c i n cin cin好像都不行。

C + + C++ C++代码如下:

#include<bits/stdc++.h>
using namespace std;
char s[100015];
int main()
{
	int n=0,ans=1;
	char ch;
	while((ch=getchar())!=EOF)s[++n]=ch;//如果有东西就继续读入
	for(int i=1;i<=n;i++)
	{
		int l=i,r=i;
		while(s[l-1]==s[r+1]&&l>1&&r<=n)l--,r++;//奇数
		ans=max(ans,r-l+1);
		l=i;r=i+1;
		if(s[l]!=s[r])continue;
		while(s[l-1]==s[r+1]&&l>1&&r<=n)l--,r++;//偶数
		ans=max(ans,r-l+1);
	}
	printf("%d\n",ans);
}

第三题 交换后的or(难度:入门~中等)

题目描述

给定两组长度为 n n n的二进制串,请问有多少种方法在第一个串中交换两个不同位置上的数字,使得这两个二进制串“”的结果发生改变?

暴力做法

枚举两个位置,然后交换,计算出是否改变,然后统计答案。
但是这样时间复杂度是 O ( n 2 ) O(n^2) O(n2)的,无法通过本题。

100分做法

考虑到交换只和修改的两个位置有关,而一个位置只有四种情况,
于是我们记录出当前每种情况各出现了多少次(如01,10等),
然后用手算出哪两种情况可以使结果发生改变,
接着统计答案即可。
注意开 l o n g long long l o n g long long
C + + C++ C++代码如下:

#include<bits/stdc++.h>
using namespace std;
int a[100005],b[100005];
int n;
long long ans,s1,s2,s3,s4;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%1d",&a[i]);
	for(int i=1;i<=n;i++)scanf("%1d",&b[i]);
	for(int i=1;i<=n;i++)
	{
		if(a[i]==0&&b[i]==0)
		{
			ans+=s3+s4;
			s1++;
		}
		if(a[i]==0&&b[i]==1)
		{
			ans+=s3;
			s2++;
		}
		if(a[i]==1&&b[i]==0)
		{
			ans+=s1+s2;
			s3++;
		}
		if(a[i]==1&&b[i]==1)
		{
			ans+=s1;
			s4++;
		}
	}
	printf("%lld",ans);
}

第四题 去除整数(难度:入门~中等)

题目描述

已知存在集合 A A A包含 n n n个整数,从 1 1 1 n n n。 存在 m m m个整数 a 1 , a 2 , . . . , a m a_1,a_2,...,a_m a1,a2,...,am。 在集合 A A A中去除这 m m m个整数的的倍数。 输出集合中包含的元素的个数。

100分做法1

发现 m ≤ 10 m\leq10 m10
于是直接搜索!
枚举当前选哪些数,然后求最小公倍数 l c m lcm lcm
如果有奇数个数,就减去 n ÷ l c m n\div lcm n÷lcm,否则加上 n ÷ l c m n\div lcm n÷lcm
最后输出答案就行了。
什么?你怎么知道这是对的?
这是容斥的板题,如果不会容斥可以上百度学习。

100分做法2

这是一种规范的容斥做法,不过时间复杂度和搜索一样。
枚举子集,然后计算出子集中的数的 l c m lcm lcm和子集中数的个数,
接着按照做法1加加减减,
最后输出答案即可。
C + + C++ C++代码如下:

#include<bits/stdc++.h>
using namespace std;
long long a[15]={};
long long gcd(long long x,long long y){return y==0?x:gcd(y,x%y);}
long long lcm(long long x,long long y){return x*y/gcd(x,y);}
int main()
{
	int m;
	long long n,tot;
	scanf("%lld%d",&n,&m);
	tot=n;
	for(int i=1;i<=m;i++)
	{
		scanf("%lld",&a[i]);
	}
	for(int i=1;i<(1<<m);i++)//枚举非空子集
	{
		long long g=-1,t=1;
		for(int j=1;j<=m;j++)
		{
			if((i&(1<<(j-1)))>0)
			{
				if(g==-1)g=a[j];
				else g=lcm(g,a[j]);
				if(g>n)break;
				t*=-1;
			}
		}
		if(g!=-1)tot+=t*(n/g);
	}
	printf("%lld\n",tot);
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值