22.3.24

这篇博客探讨了两种算法问题的解决方案。第一部分介绍了如何在O(n)时间复杂度内计算字符串中不同字符的分值和,通过维护每个字符的前缀位置来优化计算。第二部分涉及数论,解释了当两个互质的数p和q时,px+py无法表示的最大数是pq-p-q,并给出了证明。此外,还讨论了一种模拟蚂蚁行走的场景,分析了在特定条件下感染蚂蚁数量的变化情况。
摘要由CSDN通过智能技术生成

1,字串分值和;2,数论,最大不能表示的数;


1,字串分值和;

题意:string s;f(s)表示为s中不同字符的个数,如f(ab)=2,f(aa)=1;

给定一个字符串s,求;字符串长度为1~1e6;

思路:暴力想:需要预处理f[i][j]表示i到j位置的f(i,j)的值,两层for循环,一层i,一层j,相加即可;

但是这样复杂度为O(n^2);会tle;

思考一种O(n)或O(nlogn)的做法;

看这个表格,求和就是把每一行的值相加即可, 但是这是n^2行,所以换一个思路,我们去枚举每一列,把每一列中,每个字母的贡献值相加,最后每一列求和,得到的也是答案;

每个字母的贡献值:( i - pre[ i ] ) * ( n - i + 1);pre储存上次该字母出现的位置(首次为0),i为当前位置;

拿第一个A举例,它在第一位,它对它之后的所有子串都贡献一个1;所以一共贡献

(1-0)*(5-1+1)=5;

第三个A,他在 第三位,它不是第一次出现,所以它对上个A的位置之后的所有位置贡献1个1,一共贡献(3-1)*(5-3+1)=6;

#include<bits/stdc++.h>
#define rep1(i,a,n) for(int i=a;i<n;i++) 
#define rep2(i,a,n) for(int i=a;i<=n;i++) 
#define per1(i,n,a) for(int i=n;i>a;i--) 
#define per2(i,n,a) for(int i=n;i>=a;i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef double db;
const int N=1e6+10;
char s[N];
int last[N],pre[N],nxt[N];
int main()
{
//	quick_cin();
	cin>>s+1;
	int len=strlen(s+1);
	rep2(i,0,26)last[i]=0;
	rep2(i,1,len)
	{
		int x=s[i]-'a';
		pre[i]=last[x];
		last[x]=i;
	}
	//memset(last,len,sizeof last);
	rep2(i,0,26)last[i]=len;
	ll ans=0;
	rep2(i,1,len)
	{
		ans+=(i-pre[i])*(len-i+1);
	}
	cout<<ans;
	return 0;
}

2,最大不能表示的数;

对于互质的两个数p,q,px+py 不能表示的最大数为pq-p-q. 

证明过程:数论:px+py 不能表示的最大数为pq-p-q的证明 - PIPIBoss - 博客园

#include<bits/stdc++.h>
#define rep1(i,a,n) for(int i=a;i<n;i++) 
#define rep2(i,a,n) for(int i=a;i<=n;i++) 
#define per1(i,n,a) for(int i=n;i>a;i--) 
#define per2(i,n,a) for(int i=n;i>=a;i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef double db;
const int N=1e6+10;
char s[N];
int last[N],pre[N],nxt[N];
int main()
{
	quick_cin();
	int n,m;
	cin>>n>>m;
	cout<<n*m-n-m;
	return 0;
}

 3,蚂蚁感冒

利用蚂蚁走路的特性去解,不要想着啥啊碰头了传染,然后还要掉头啥的;就是把它看成穿过去了就好,只是碰到感染的,它也变成感染的;

所以只要需要找出,在第一个感染蚂蚁左边的往右走的,右边的往左走的蚂蚁总数即可;

但是这是在必须有 左边往右走并且 右边往左走才成立

假如感染蚂蚁往右走,左边有一个往右走走的,右边全是往右走的,那么最终感染的蚂蚁有几个呢,是1个,因为右边没有往左走的,所以不会碰到感染蚂蚁,也就不会碰到左边往右走的,径统统不成立了,所以必须加个判断条件;

若感染者蚂蚁右走,if(abs(a[i])>flag&&a[i]<0),找出右边往左走的则成立;
若感染者蚂蚁左走,if(abs(a[i])<abs(flag)&&a[i]>0),找出左边往右走的则成立;
#include<bits/stdc++.h>
#define rep1(i,a,n) for(int i=a;i<n;i++) 
#define rep2(i,a,n) for(int i=a;i<=n;i++) 
#define per1(i,n,a) for(int i=n;i>a;i--) 
#define per2(i,n,a) for(int i=n;i>=a;i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef double db;
const int N=1e6+10;
int a[N];
int main()
{
	quick_cin();
	int n,flag;
	int ans=1;
	cin>>n;
	cin>>flag;
	rep2(i,2,n)cin>>a[i];
	if(flag>0)
	{
		rep2(i,2,n)
		{
			if(abs(a[i])>flag&&a[i]<0)
			{
				rep2(j,2,n)
				{
					if(abs(a[j])<flag&&a[j]>0)ans++;
					else if(abs(a[j])>flag&&a[j]<0)ans++;
				}
				cout<<ans;
				return 0;
			}
		}
		cout<<1;
		return 0;
	}
	else
	{
		rep2(i,2,n)
		{
			if(abs(a[i])<abs(flag)&&a[i]>0)
			{
				rep2(j,2,n)
				{
					if(abs(a[j])<abs(flag)&&a[j]>0)ans++;
					else if(abs(a[j])>abs(flag)&&a[j]<0)ans++;
				}
				cout<<ans;
				return 0;
			}
		}
		cout<<1;
		return 0;
	}
	cout<<ans;
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dull丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值