日期:2023.10.3
学号:s07661
一.比赛概况:
总分400分,拿到220分,其中第1题100分,2题100分,3题20分,4题0分,
二. 比赛过程
前三题暴力枚举,第四题直接不会
三. 解题报告
一.重复判断
1.题目大意
小可需要判断一个字符串a,是否由另一个字符串b生成出来的,所谓的生成,其实就是把字符串b重复若干次,即:判断字符串a是否是字符串b重复若干次得到的。
2.比赛中的思考
新定义一个字符串,while(新字符串长度小于字符串a长度)拼接字符串b,判断拼接后是否等于字符串a
3.解题思路
上面思路,还可以while改for
4 .AC代码
#include<bits/stdc++.h>
using namespace std;
int t;
string s,s1;
int main(){
cin>>t;
while(t--){
cin>>s>>s1;
int x=s.size(),y=s1.size();
if(x%y!=0){
cout<<"NO";
continue;
}
string s2="";
while(s2.size()<s.size()){
s2+=s1;
}
if(s2==s){
cout<<"YES"<<"\n";
}
else{
cout<<"NO"<<"\n";
}
}
return 0;
}
二.歪果仁学乘法
1.题目大意
歪果仁不太会乘法,原因是他们被不过九九乘法表,小可听到之后,提出了一种不需要九九乘法表也可以计算乘法的方式,对于a × b:
1.将a,b的每一位上的数码画成线,不同位之间分隔开。
2.a 和 b 的方向垂直画出。
3.数出每个方向上交点的个数,即是 c 对应位置上的数码
求它们的乘积时交点的总个数是多少。
2.比赛中的思考
用两个循环求数位,两层循环逐位相乘,输出结果
3.解题思路
上面解法或如下:
cout<<(n%10*(m%10))+(n%10*(m/10))+(n/10*(m/10))+(n%10*(m/10));
4 .AC代码
自己的解法:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,m,a[10],a1[10];
cin>>n>>m;
int t=n,t1=m,cnt=0,cnt1=0;
while(t>0){
a[++cnt]=t%10;
t/=10;
}
while(t1>0){
a1[++cnt1]=t1%10;
t1/=10;
}
int sum=0;
for(int i=1;i<=cnt;i++){
for(int j=1;j<=cnt1;j++){
sum+=a[i]*a1[j];
}
}
cout<<sum;
return 0;
}
正解:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,m,a[10],a1[10];
cin>>n>>m;
cout<<(n%10*(m%10))+(n%10*(m/10))+(n/10*(m/10))+(n%10*(m/10));
return 0;
}
三. 去重求和
1.题目大意
小可有一个长度为 n 的序列 ai。他定义sum(l,r),为a[l] ~ a[r] ,这些数去重之后的和。请求出for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)sum(i,j);
2.比赛中的思考
暴力枚举
3.解题思路
定义桶,计算每个数第一次出现时产生的贡献。设为最大的,然后求出公式(n-i+1)*a[i]*(i-mp[a[i]])加到计数器中,再对桶进行标记,最后输出计数器中的值%1e9+7(最好是边计算边取余)
4 .AC代码
暴力如下:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,a[500005];
ll sum,ans;
const int mod=1e9+7;
map<ll,ll> mp;
int main(){
cin>>n;
for(ll i=1;i<=n;i++){
cin>>a[i];
}
for(ll i=1;i<=n;i++){
sum=0;
for(ll j=i;j<=n;j++){
if(mp.count(a[j])==0){
sum+=a[j];
mp[a[j]]=1;
}
ans=(sum+ans)%mod;
}
mp.clear();
}
cout<<ans;
return 0;
}
AC代码如下:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,a[500005],p[500005];
ll sum,ans;
const int mod=1e9+7;
map<ll,ll> mp;//定义桶
int main(){
cin>>n;//输入
for(ll i=1;i<=n;i++){
cin>>a[i];
mp[a[i]]=0;//桶标记
}
for(int i=1;i<=n;i++){
ans=ans+(n-i+1)%mod*a[i]%mod*(i-mp[a[i]])%mod;//计算公式
ans%=mod;//因为结果超过ll类型,所以一步取余一次
mp[a[i]]=i;//标记
}
cout<<ans%mod;
return 0;
}
四. 点集操作
1.题目大意
1.任选不同的两个点i,j
2.称 Ai 为 i 能到达的所有点组成的点集,Aj 为 j 能到达的所有点组成的点集 。(注意:每个点可以到达的点集包含这个点本身)
3.设 B 为一个最大的点集,满足 B 既是 Ai 的子集,又是Aj的子集 。
4.将 B 在图中变成一个新点,B 内的所有边全部删除。点集 B 以外的点与点集 B 以内的点的连边关系转移到新点上。
2.比赛中的思考
不会怎么办??????
3.解题思路
图邻接表存储,遍历
4 .AC代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
vector<vector<int>> v;
vector<int> vis,ind;
int ans;
int n,k;
int main(){
cin>>n>>k;//输入
v.resize(n+1);
ind.resize(n+1);
vis.resize(n+1);//初始大小
for(int i=1;i<=k;i++){
int x,y;
cin>>x>>y;
v[x].push_back(y);//vector存储
++ind[y];
}
for(int i=0;i<v.size();i++){
if(ind[i]){
for(int j=0;j<v[i].size();j++){//遍历
vis[v[i][j]]=1;//标记没剩
}
}
}
for(int i=1;i<=n;i++){
if(vis[i]==0)ans++;//判断是否剩下了
}
cout<<ans;
return 0;
}
总结:这几天模拟赛还行吧,但题难了就不知道变通,对知识点掌握的不熟悉,最后这15天要好好复习知识点,好好刷题,努力拿奖!