题干:
链接:https://ac.nowcoder.com/acm/contest/1080/E
来源:牛客网
tokitsukaze有一个长度为n的字符串,字符串仅包含'0'-'9'。
tokitsukaze要把这个字符串切割成若干个子串,每个子串作为一个十进制的数,能被3整除,且不含前导0。
问有多少种切割的方案。由于答案可能很大,请输出mod 998244353 后的结果。
输入描述:
第一行包含一个正整数n,(1≤n≤10^5)。 第二行包含一个长度为n的字符串s,('0'≤s[i]≤'9')。
输出描述:
输出一个整数,表示方案数,mod 998244353 后的结果。
示例1
输入
复制
1 1
输出
复制
0
示例2
输入
复制
1 0
输出
复制
1
示例3
输入
复制
4 1203
输出
复制
3
说明
(1) 1203 (2) 120|3 (3) 12|0|3 所以方案数为3。 注意:12|03,视作不合法,因为有前导0。
解题报告:
看似一个dp题,其实直接递推就可以了。其实如果数字中没有0的话直接一个变量就可以了。但是这题有零所以需要开两个变量。
先来一个TLE代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define FF first
#define SS second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 2e5 + 5;
const ll mod = 998244353;
char s[MAX];
ll dp[MAX];
int cur,tmp,n;
int main()
{cin>>n;cin>>(s+1);for(int i = 1; i<=n; i++) s[i] -= '0';dp[0] = 1;for(int i = 1; i<=n; i++) {cur = (cur+s[i])%3;tmp = cur;for(int j = i; j>=1; j--) {tmp = (tmp+9-s[j])%3;if(!tmp && cur == tmp && (s[j]!=0 || j==i)) dp[i] = (dp[i] + dp[j-1]) % mod;}}ll ans = 0;printf("%lld\n",dp[n]%mod);return 0 ;
}
可以发现可以化简成这样:(来自题解)
for(int i=1;i<=n;i++) dp[i]=0;
dp[0]=1;
for(int i=1;i<=n;i++)
{suf=0;for(int j=i;j;j--){suf=(suf+s[j]-'0')%3;if(s[j]=='0'&&j<i) continue;if(!suf) (dp[i]+=dp[j-1])%=mod;}
}
也就是说特点就是要找前缀数字和是0的方案数,然后累加一下就行了。但是因为有前导0,所以要开两个变量分别记录。
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define FF first
#define SS second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 2e5 + 5;
const ll mod = 998244353;
char s[MAX];
ll dp,sum;
int cur,tmp,n;
int main()
{cin>>n;cin>>(s+1);sum = 1;for(int i = 1; i<=n; i++) s[i] -= '0';for(int i = 1; i<=n; i++) {cur = (cur+s[i])%3;if(cur == 0) {if(s[i] == 0) sum = (sum+dp)%mod;else sum = dp = (sum+dp)%mod;}}if(cur == 0) printf("%lld\n",sum);else printf("0\n");return 0 ;
}