目录
一.重复判断
1.题目描述
判断一个字符串a,是否由另一个字符串b重复若干次得到的。
2.思路
(1)用find函数在a中循环查找b,找到后标记为“*”,结束后若数组中全是“*”那么a就是是否由另一个字b重复得到的。
(2) j表示当前匹配到b字符串的第j位。i表示当前匹配到a字符串的第i位,两两比较,如果t等于t.size(),说明一遍已经复制完了,从零开始重新匹配。
下面是思路(1)的
3.AC代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
string a,b;
long long al=0,bl=0,te=0,t;
cin>>t;
while(t--)
{
cin>>a>>b;
al=a.size(),bl=b.size(),te=0;
while(1)
{
te=a.find(b);
if(te==-1)
{
break;
}
for(int i=0;i<bl;i++)
{
a[te+i]='*';
}
}
te=0;
for(int i=0;i<al;i++)
{
if(a[i]!='*')
{
te=1;
cout<<"NO"<<endl;
break;
}
}
if(te==0)
{
cout<<"YES"<<endl;
}
}
return 0;
}
二.歪果仁学乘法
1.题目描述
歪果仁不太会乘法,原因是他们被不过九九乘法表,对于a × b:
1.将a,b的每一位上的数码画成线,不同位之间分隔开。
2.a 和 b 的方向垂直画出。
3.数出每个方向上交点的个数,即是 c 对应位置上的数码。
给出两个数字 a, b,求它们的乘积时交点的总个数是多少
2.思路
找规律:因为所以将a、b拆分成十位和个位两个数字,然后两两求交点数即可。
注意:不能算出来以后再求各数位和,有的数据不是这个规律
3.AC代码
#include<bits/stdc++.h>
using namespace std;
int hhh(int a, int b)
{
int a1=a/10,a2=a%10,b1=b/10,b2=b%10;
return a1*b1+a1*b2+a2*b1+a2*b2;
}
int main()
{
int a,b;
cin>>a>>b;
cout<<hhh(a,b);
return 0;
}
三.去重求和
1.题目描述
定义sum(l,r)sum(l,r),为a[l]a[l] ~ a[r]a[r] ,这些数去重之后的和。
请求出
2.思路
我们只计算每个数第一次出现时产生的贡献。设pi为最大的j<i使得 aj=ai(不存在则为0),
那么在这种方式下, 在答案中的系数就是(i-pi)(n-i+1)。
计算 可以使用 map(用桶会爆)做到 ,那么算法的时间复杂度就是。
3.AC代码
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
typedef long long ll;
const int mod = 1e9 + 7;
int n,a[N];
map<int,int>mp;
int l[N],r[N];
int main()
{
cin>>n;
for(int i=1;i<=n;++i)
{
cin >> a[i];
mp[a[i]] = 1;
}
mp.clear();
for(int i = 1; i <= n; ++i)
{
l[i] = mp[a[i]] + 1;
mp[a[i]] = i;
}
ll ans = 0;
for(int i = 1; i <= n; ++i)
{
ans += 1ll * a[i] * (i - l[i] + 1) % mod * (n - i + 1) % mod;
ans %= mod;
}
cout << ans << endl;
}
四.点集操作
一.题目描述
有一个有向无环图,对这个图做任意次modify(i,j)操作之后的图中剩余的最小点数,其中,其中modify(i,j)为一次操作:
1.任选不同的两个点i,j
2.称 Ai 为 i 能到达的所有点组成的点集,Aj 为 j能到达的所有点组成的点集 。(包含这个点本身)
3.设 B 为一个最大的点集,满足 B 既是 Ai 的子集,又是Aj的子集 。
4.将 B 在图中变成一个新点,B 内的所有边全部删除。点集 B 以外的点与点集 B 以内的点的连边关系转移到新点上。
二.思路
样例可得,把有入度的相关点的重叠点,变成一个大点B,是一次modify操作。
整体把1、4、5点,合成一个大点,最终变成3个点。
要是把5 4边去掉,就没有融合的大点,最小点数,仍然保持5个点。
发现在一个单向链上,只需要让链头的两个点进行一次操作就可以将整个链变成两个点。
所以每次操作可以在一条所含点数超过 2 的单向链上进行,直至不能继续操作,剩下的点的个数即为图中剩余的最小点数。
由上面操作的特殊性可以知道所有入度为 0 的点删不掉,所有满足所有入边对应点入度为 0 的点也删不掉,可以将这些点(满足所有入边对应点入度为 0 的点)看成新点。统计这些点个数即可。
复杂度:
三.AC代码
#include<bits/stdc++.h>
using namespace std;
const int mn=1e6+5;
int n,m,x[mn*2],y[mn*2],in[mn];
int head[mn],num=0,ans;
bool b[mn],vis[mn];
vector<int>v;
struct hhh
{
int to,next;
}e[mn*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;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~THE END~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~