Codeforces 1005D - Polycarp and Div 3 模拟

题目:给你一个超大超大的数,让你用隔板把数字分开,问最多能分出多少个小部分,这些小部分都能被三整除。
吐槽:今天下午一看这题,感觉不难,感觉像是区间dp,是我怵头的区间dp。。。脑子就大了就想用区间dp的方法解决它。。。然鹅并没有成功,也并不会做,所以顺便爆0了。然后看了看lc大佬share的源代码,恍然大悟模拟就行。不难。

放了两个代码 一个是超简单模拟,一个是(半)尺取法哈哈哈,是看了smy大佬之后写出来的!

思路:首先肯定是用字符串来存。int不可能 longlong不可能 longlong*10086也不可能。然后遍历。怎么个遍历方法呢?怎么样才能算作可以划分呢?问得好。
首先我们处理字符串的每一位数的时候,都把它模三取余,也就是说这个字符串实际上就是一串由0、1、2三个数字组成的数。
我现在说一句话:至多连续三个数,必能出现三的倍数
不信?下面有三大保障~:
第一重保障:若第一位模3是0也就是说是3的倍数,那就直接可以算作一个,ans++,下一个又是新的一个。若不是3的倍数,就先把它取余后的数加到sum,用一个cnt记录存了几个数了。
第二重保障:然后下一个数,若加到sum里之后,sum模3为0,那么说明这俩可以凑起来3的倍数了,那sum和计数的cnt都清零,开始新的计数。
第三重保障:倘若前两个都不行,那第三个数的加入一定能凑出一个三的倍数。
为什么呢?
来看这里:举例子吧,若第一个第二个没能凑成3,那要么是1 1,要么是2 2,那这两种情况下,不论第三个数是出现0、1、2,中的任意一个,都可以凑出个3来。若第三个是0,那么直接可以,若第三个是1,可以和1 1 凑成3,也可以和2 2 的第二个2凑成3。所以一定能凑出3的倍数的!
下面是AC代码,再次模lc大佬。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;//简单模拟方法! 
int main(){
	string s;
	cin>>s;
	int ans=0; 
	int t=0,sum=0,cnt=0;//t用来记录当前是几 sum来记录当前数字(模后)之和 cnt用来记录当前几个数了 
	for(int i=0;i<s.size();i++){//最多每三个必确定一个 
		int t=(s[i]-'0')%3;//第一保障 
		sum=(sum+t)%3;//第二保障 
		cnt++;//第三保障 
		if(t==0||sum==0||cnt==3){
			ans++;
			sum=0,cnt=0;//清零 也重新数 
		}
	}
	printf("%d\n",ans); 
	return 0;
}

下面是(半)尺取法

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;//尺取法
char s[200005];
int main() {
	scanf("%s",s);
	int ans=0;
	for(int i=0; i<strlen(s); i++) {
		int a=(s[i]-'0')%3;
		if(a==0) { //若可以直接++
			ans++;
			continue;
		} else if(i+1<strlen(s)) {
			int b=(s[i+1]-'0')%3;
			if(b==0||(a+b)%3==0) {
				ans++;
				i++;
				continue;
			} else if(i+2<strlen(s)) { //若还得需要下一个
				ans++;
				i+=2;
				continue;
			}
		}
	}
	printf("%d\n",ans);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值