CSP-J复赛模拟5赛后补题报告

本文记录了一位参赛者在2023年10月3日的编程比赛经历,涉及四个题目:字符串重复判断、乘法学习、去重求和和点集操作。作者分享了解题思路和代码,强调了时间管理和基础题目的重要性。
摘要由CSDN通过智能技术生成


日期:2023年10月3日星期四
      学号:S08683

                                                                      姓名:王皓轩
1. 比赛概况:
比赛总分共 4 题,满分 400,赛时拿到 200 分,其中第一题100分:),第二题100分:),第三题0分:(,第四题0分:(。
2. 比赛过程:
第一题很水,用了一个for判断就直接过了。
然后做第二题用也和第一题差不多,数位分离过了。
第三题做算出来一个公式,样例和几个自己试的都能过,但没分。
第四题,写了写前向星,但是操作实在是没读懂。
3. 题解报告:
(1) 第一题:重复判断
情况:赛中100分,已补题
题意:有T组,输入一个字符串a和一个字符串b,看a是不是b重复形成的。
样例:输入:2  
            usbusb usb
            ggbggb  ggp
      输出:YES
            NO
赛时本题做题想法:这很明显那就是一道水题,我直接用之间的倍数for循环累加第二个字符串,如果累加后相等,直接YES,否则NO。
题解:题解里使用了一个for双指针从a身上一位一位对比,i代表a的一位,j代表b的位置,然后多次用b来判断一整个a。
AC 代码(我自己的):

#include<bits/stdc++.h>
using namespace std;
int t;
int main()
{
	//freopen("repeat.in","r",stdin);
	//freopen("repeat.out","w",stdout);
	cin>>t;
	while(t--){
		string s,b,s1;
		cin>>s;
		cin>>b;
		int len1=s.size(),len2=b.size();
		if(len1%len2!=0){
			cout<<"NO"<<endl;
		}
		else{
			s1=b;
			for(int i=2;i<=len1/len2;i++){
				s1=s1+b;
			}
			//cout<<len1/len2<<" "<<s1;
			if(s1==s){
				cout<<"YES"<<endl;
			}
			else{
				cout<<"NO"<<endl;
			}
		}
		
	}
	//fclose(stdin);
	//fclose(stdout);
	return 0;
}
 


 
(2) 第二题:歪果仁学乘法
情况:赛中100分,已补题。
题意:歪果仁想学乘法,但不会九九乘法表,所以发现了另一种方法:
 
求出点数有多少。
样例:12 13              12
数据:1<=a,b<=99
赛时本题做题想法:直接数位分离,然后头乘头尾乘尾,头乘尾,尾乘头,然后加起来,直接AC。
题解:与我的想法一毛一样:)。
AC 代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,a[5],b[5],tot1,tot2;
int main()
{
	//freopen("multiplication.in","r",stdin);
	//freopen("multiplication.out","w",stdout);
	cin>>n>>m;
	int c=n,x=m;
	while(c!=0){
		a[++tot1]=c%10;
		c/=10;
	}
	while(x!=0){
		b[++tot2]=x%10;
		x/=10;
	}
	if(n<=10&&m<=10){
		cout<<n*m;
	}
	else{
		cout<<b[2]*a[2]+a[2]*b[1]+a[1]*b[2]+a[1]*b[1];
	}
	//fclose(stdin);
	//fclose(stdout);
	return 0;
}



(3) 第三题:去重求和
情况:赛中0分,已补题。
题意:小可有一个长度为n的序列ai,他定义sum(l,r)为a[l]~a[r],这些数去重之后的和,求出∑n l=1 ∑n r=1
sum(l,r),答案对10^9+7取模。
赛时本题做题想法:一开始没弄明白,但列了几个样例后发现第i个位置的数会出现n-i+1次,然后先不考虑重复,把所有的都加起来,然后减,但应该是减写错或者数据太大,导致零分。
题解:去重就算第一次出现的贡献,为用现在的位置-原来出现过的位置*(n-i+1)*a[i].
AC 代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5,M=1e9+7;
typedef long long ll;
ll n,a[N],L[N];
map<int,int>mp;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i]; 
		mp[a[i]]=1;
	}	
	for(int i=1;i<=n;i++){
		L[i]=mp[a[i]];
		mp[a[i]]=i+1;
		//cout<<L[i]<<endl;
	}
	ll ans=0;
	for(int i=1;i<=n;i++){
		ans+= a[i]*(i-L[i]+1)%M*(n-i+1)%M;
		ans%=M;
	}
	cout<<ans%M;
	return 0;
} 


(4) 第四题:点集操作
情况:赛中0分,已补题。
题意:有一个有向无环图,求做任意次modify(i,j)操作后的最小点数1<=i,j<=n
操作过程:1. 任选不同的两个点i,j
2. 称Ai为i能到达的所有点组成的点集,Aj为j能到达的所有点组成的点集 。(注意:每个点可以到达的点集包含这个点本身)
3. 设 B 为一个最大的点集,满足 B 既是Ai的子集,又是Aj的子集 。
4. 将 B 在图中变成一个新点,B 内的所有边全部删除。点集 B 以外的点与点集 B 以内的点的连边关系转移到新点上。
赛时本题做题想法:做了个链式前向星,但是操作是真没看懂怎么减少次数和时间。
题解:画图可得,其实有入度的相关点的重叠点,变成点B为一次操作,但发现如在一条单向链中,一次操作就能变为两个点,所以一直在单向链上模拟(点数需),直至不能操作,剩下的电机为剩余的最小点数。
AC 代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int n,m,x[maxn*2],y[maxn*2],in[maxn*2];
int head[maxn],num,ans;
vector<int>v;
bool b[maxn],vis[maxn];
struct node{
	int to,next;
}e[maxn*2];
void add(int u,int v){
	e[++num].to=v;
	e[num].next=head[u];
	head[u]=num;
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>x[i]>>y[i];
		add(x[i],y[i]);
		in[y[i]]++;
	}
	for(int i=1;i<=n;i++){
		if(!in[i]){
			v.push_back(i);
			ans++;
		}
	}
	for(int i=1;i<=m;i++){
		if(in[x[i]])b[y[i]]=1;
	}
	for(int i=0;i<v.size();i++){
		for(int j=head[v[i]];j;j=e[j].next){
		    if(!b[e[j].to]){
		    	b[e[j].to]=1;
		    	ans++;
			}
		}
	}
	cout<<ans;
	return 0;
}


4. 赛后总结:
这次比赛其实相对来说比前面简单很多,但是在第三题上我为了列样例而花了很多时间(关键是还报0了),导致第四题几乎没时间看,就草草地写了一下,也没有画图分析。以后应该更注意时间的分配,多多动笔计算!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值