1.重复判断
题目描述
小可需要判断字符串a是否是字符串b重复若干次得到的。输入一个数字 t,表示共有 t 组询问。接下来 t 行每行两个字符串 a 和 b。输出 t 行,每行输出 YES
或NO。
思考
如果a不
是字符串b重复若干次得到的,长度相除的余数不会是零(不能整除),输出NO。便利字符串a,每次将a中长度与b长度相等的子串和b进行比较,一次不相等,则输出NO,否则输出YES。
思路
和比赛中的思考相同。
AC代码
#include<iostream>
#include<string>
using namespace std;
int main(){
// freopen("repeat.in","r",stdin);
// freopen("repeat.out","w",stdout);
int t;
string a,b;
cin>>t;
while(t--){
cin>>a>>b;
int f=0,l=0,len=b.size();
if(a.size()%len!=0){
cout<<"NO"<<endl;
continue;
}
while(l+len<=a.size()){
if(a.substr(l,len)!=b){
f=1;
break;
}
l+=len;
}
if(f==1) cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
// fclose(stdin);
// fclose(stdout);
return 0;
}
2.歪果仁学乘法
题目描述
对于a × b:(1<=a,b<=99)
1.将a,b的每一位上的数码画成线,不同位之间分隔开。
2.a 和 b 的方向垂直画出。
3.数出每个方向上交点的个数,即是 c 对应位置上的数码。
请给出两个数字 a, b,求它们的乘积时交点的总个数是多少。
计算12 ×13的方法:
1.红色线分别画出 1 条和 2 条;
2.蓝色线分别画出 1 条和 3 条;
3.数出红、蓝色线的交点个数,依次为 1,5,6 个;
思考
a,b是两位数, 只要把a的十位数和b的十位数、a的个位数和b的十位数、只要把a的十位数和b的个位数、a的个位数和b的个位数 的乘积相加就知道交点的总个数了。
思路
和比赛中的思考相同。
AC代码
#include<iostream>
using namespace std;
int main(){
// freopen("multiplication.in","r",stdin);
// freopen("multiplication.out","w",stdout);
int a,b,sum=0;
cin>>a>>b;
cout<<(a/10)*(b%10)+(a/10)*(b/10)+(a%10)*(b%10)+(a%10)*(b/10);
// fclose(stdin);
// fclose(stdout);
return 0;
}
3.去重求和
题目描述
小可有一个长度为 n 的序列 ai。他定义sum(l,r),为a[l]~a[r] ,这些数去重之后的和,请求出
输入一个正整数 n ,表示序列长度。输入n个整数,表示序列 a ,答案对10^9+7109+7取模。(1≤n≤5∗10^5,1≤ai≤10^9)
思考
使用暴力解法,遍历a数组从l到r,用map去重。循环遍历map,如果是1,a数组从l到r的加和就加等于k,最后算出所有加和的总和。
思路
a1,a2,a3,a4,a5......,an
a1 a2出现次数=a1出现次数-1;
a1 a2
a1 a2 a3
a1 a2 a3 a4...............
a1 a2 . . . . . . .an ai
出现次数=aj出现次数-(i-j);
a[1]~a[n]中a1重复计算n次;a[1]~a[n]中a2重复计算n-1次,a[2]~a[n]中重复计算n-1次,
可以发现a[1]计算了(n-1+1)*1次,a[2]计算了(n-2+1)*2次,那么a[i]计算了(n-i+1)*i次。
而在去重时a[i]重复会比第一次出现少算第一次出现的位置次,所以可以将map[a[i]]赋为0,表示还未出现,出现第一次标记下标。
AC代码
#include<iostream>
#include<map>
using namespace std;
const long long mod=1e9+7;
long long n,a[500005],pos=0;
map<long long,long long> mp;
long long ans=0;
int main(){
// freopen("summation.in","r",stdin);
// freopen("summation.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++){cin>>a[i];mp[a[i]]=0;}
for(int i=1;i<=n;i++){
ans=(ans+((i-mp[a[i]])*(n-i+1))%mod*a[i])%mod;
mp[a[i]]=i;
}
cout<<ans;
// fclose(stdin);
// fclose(stdout);
return 0;
}
4.点集操作
题目描述
对于任选不同的两个点i,j,设 B 为一个最大的点集,满足 B 既是 Ai 的子集,又是Aj的子集 。将 B 在图中变成一个新点,B 内的所有边全部删除。点集 B 以外的点与点集 B 以内的点的连边关系转移到新点上。
思考
给x到y加边,用dfs搜索i,j可以到达的点,便利找出最大相同子集,把与最大相同子集连接的点重新连到一个新点上,重复执行,最后输出剩余点数。
思路
邻接表或邻接矩阵存储图,图是无环的,所有我们知道只有出度的点能到达的点一定比有入度的点多,因此只要取只有出度的点为i,下一个有入度的点为j就能保证子集最大,剩余点数最小。
AC代码
#include<iostream>
#include<vector>
using namespace std;
int n,m,ans;
vector<vector<int> > v;
vector<int> vis,ind;
int main(){
// freopen("point.in","r",stdin);
// freopen("point.out","w",stdout);
cin>>n>>m;
v.resize(n+1);
vis.resize(n+1);
ind.resize(n+1);
while(m--){
int x,y;
cin>>x>>y;
v[x].push_back(y);
++ind[y];
}
for(int i=1;i<=n;i++){
if(ind[i]){
for(int j=0;j<=v[i].size();j++){
vis[a[i][j]]=1;
}
}
}
for(int i=1;i<=n;i++){
if(vis[i]==0){
ans++;
}
}
cout<<ans;
// fclose(stdin);
// fclose(stdout);
return 0;
}