B3832 [NICA #2] 回来吧我的小波 - 题解
本题第一篇题解,本人第二篇题解。
(考场上脑子一片空白,卡在暴力做不出来了,赛后才想到正解,就差这一题啊……)
题目大意
题目传送门
对于一个不含
现给定一个不含
解题思路
容易想到一个暴力的方法:枚举所有的子串,对于每个子串,枚举
可惜这样的算法效率过于低下,时间复杂度大概是
经过仔细的思考,我们会发现一些性质:
- 一个子串如果是好的,则包含它的串也是好的;
- 一个串如果有相同的数字,那么它是好的(
x\mid x ); - 一个串如果含有
1 ,则大概率是好的(1\mid x ,除非这个1 在最后); - 一个串如果比较长,则大概率是好的……
且慢!这里的“比较长”是多长?换句话说,是不是足够长的串一定是好的?这个“足够长”是多长?
然后我们会发现,由于串中只有
于是,我们只需要用上述暴力做法,数一数串长
时间复杂度大概是
(这过的也比较玄学,但是半秒过掉了,应该是因为常数小,跑不满……?还是我复杂度式子推错了?)
代码
细节见代码和注释,还有就是开 long long。
#include<iostream>
#include<string>
using namespace std;
string s;
long long ans,n,cnt; //记得开 long long
int val(int pos,int x,int y) { // 从 pos+x 到 pos+y 组成的数值
int ans=0;
for (int i=x;i<=y;i++)
ans=ans*10+s[pos+i]-'0';
return ans;
}
bool judge(int pos,int len) { // 判定 pos 开始长为 len 是否为好的
for (int i=0;i<len;i++) // 暴力枚举
for (int j=i;j<len;j++)
for (int k=j+1;k<len;k++)
for (int l=k;l<len;l++) {
int a=val(pos,i,j);
int b=val(pos,k,l);
if (b%a==0)
return true;
}
return false;
}
int main() {
cin>>s;
n=s.size();
for (int d=2;d<=9;d++) // 只看长度不超过 9 的串
for (int i=0;i<=n-d;i++)
if (judge(i,d))
cnt++;
ans=n*(n+1)/2;
for (int d=1;d<=9 && d<=n;d++)
ans-=n-d+1; // 计算长度超过 9 的子串数
ans+=cnt;
cout<<ans<<endl;
return 0;
}
本人第二篇题解,如有问题和建议欢迎指出!