CSP-J模拟赛五补题报告

日期:2023-10-04

学号:S12418

一:

总分数:40

T1【重复判断(repeat)】:0

T2【歪果仁学乘法(multiplication)】:40

T3【去重求和(summation)】:0

T4【点集操作(point)】:0

二、比赛过程

第一题低级错误

第二题考虑不周

第三题时间超限

第四题和没写差不多(

讽刺的是,考试结束自己测的T1T2立马全100了

(没错今天的情况和昨天几乎一模一样)

三、比赛分析

T【重复判断(repeat)】:
1、题目大意

给定两个字符串,判定a是否由完整的b构成。

2、比赛中的思考

借鉴了昨天不合法字符串那题的思路,还加了许多的特判

可是还是没对

3、解题思路

同昨天 当a[i]为b的结尾时,判断在之前b.size()个字符是否是b 不是就cout<<"NO"

4、AC代码
 

#include<iostream>
#include<string>
using namespace std;
int t;string a,kodori;
int main(){
	cin>>t;
	while(t--){
		int flag = 1;
		cin>>a>>kodori;
		int n = (int)a.size();
		a = " "+a;
		
		for(int i = 1;i<=n;i+=kodori.size()){
			if(a.substr(i,kodori.size()) !=kodori){
				flag = false;
				break;
			}
		}
		if(flag == true){
			cout<<"YES"<<endl;
		}
		else cout<<"NO"<<endl;
		}

	return 0;	
}

T2【歪果仁学乘法(multiplication)】:
1、题目大意

大水题

求出(a%10*b%10)+(a/10*b%10)+(a%10*b/10)+(a/10*b/10)的值

是个人都能对(

2、比赛中的思考

一眼野生大水题

想都没想就写了个for循环交上去了

喜提40pts

3、解题思路

就一行,即为上面表达式的值

4、AC代码(短到离谱)

#include<bits/stdc++.h>
using namespace std;
int main(){
	int a,b;cin>>a>>b;
	cout<<(a%10*b%10)+(a/10*b%10)+(a%10*b/10)+(a/10*b/10)<<endl;
	return 0;
}



















T3【去重求和(summation)】:
1、题目大意

给定一个序列,让你求出Σ(n,l = 1)Σ(n,r = 1)sum(l,r)%1e9+7的值

(人话:对于所有可能的区间去重求和最后加一起)

2、比赛中的思考

三重循环,不出意料爆了

3、解题思路

说实话我也没彻底搞懂

首先输入

然后对于第一个出现的元素,将ta的mp设定为1

接下来(不是第一个)mp的值就是下标

干啥用呢?有大用

对于两个相同值之间的部分,可以视为一个块。对这个块套一下乘法原理,就可以得出当前块的ans

最后的最后,把ans累加起来即可

4、AC代码

#include<iostream>
#include<map>
#define ll long long
using namespace std;
map<int,int>mp;
ll n,a[10000007],ans,flag,l[10000007],r[10000007];
int main(){
	cin>>n;
	for(int i = 1;i<=n;i++){
		cin>>a[i];
	}
	for(int i = 1;i<=n;i++){
		l[i] = mp[a[i]]+1;
		mp[a[i]] = i;
	}
	for(int i = 1;i<=n;i++){
	    ans+=1ll*a[i]*(i-l[i]+1)%1000000007*(n-i+1)%1000000007;
	    ans%=1000000007;
	}
	cout<<ans;
	return 0;
}

T4【点集操作(point)】:
1、题目大意

给定一个有向图,把最大数量共同结点合并为一个,求合并后结点数。

2、比赛中的思考

别看我现在把题面写的这么简单,但是考试时我一点没明白

所以这题只能骗分 但一分没骗到

3、解题思路

链表具体实现,外加一手vector

通过特性来寻找(特性:第一个共同节点在一条链里出现过,在另一条链里也出现过)

所以我们将第一个寻找到的结点设为“代表”即可

只有出度的一定没法删掉,只有入度的一定会被删

最后输出次数,完成。

4、AC代码

#include<iostream>
#include<cstring>
#include<vector> 
using namespace std;
const int N = 1e6+5;
int n,m,x[N*2],y[N*2],in[N];
int head[N],ver[2*N],Next[2*N],tot = -1,ans;
bool b[N],vis[N];
vector<int>v;
void add(int x,int y){//链式前向星
    ver[++tot]=  y;
    Next[tot] = head[x];
    head[x] = tot;
}
int main(){
    memset(head,-1,sizeof head);
	cin>>n>>m;//n个点 m条边
	for(int i = 1;i<=m;i++){//输入m条边
	    cin>>x[i]>>y[i];//输入x~y有一条有向边
	    add(x[i],y[i]);//链式前向星
	    in[y[i]]++;//统计入度
	}
	for(int i = 1;i<=n;i++){
	    if(!in[i]){//如果入度为零
	        v.push_back(i);//记录入度为零的点,最外层的点一定没法删
	        ans++;//没法删的点+1
	    }
	}
	for(int i = 1;i<=m;i++){
	    if(in[x[i]]){//x[i]不是第一层的点
	        b[y[i]] = 1;//标记层数>2的点
	    }
	}
	for(int i = 0;i<v.size();++i){//没有入度的最外层
	    for(int j = head[v[i]];~j;j = Next[j]){//第二层
	        int y = ver[j];//一定是第二层的点
	        if(!b[y]){//第二层的点又是>2层的点,不会进v,不用算,作为代表
	            b[y] = 1;
	            ans++;//合并后的新点标记
	        }
	    }
	}
	cout<<ans;
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值