Description
给定一个由数字(0-9)构成的字符串s。我们可以由此定义出size(s) * size(s) 大
小的矩阵b,其中b[i][j] = s[i] * s[j];请问在这个矩阵b中,有多少子矩形满足其中的b[i][j]的和为另一个给定的数字a。
Input
第一行一个整数a。
第二行字符串s。
Output
一个整数表示满足条件的子矩形数。
Sample Input
10
12345
Sample Output
6
【样例解释】
b 矩阵为:
01 02 03 04 05
02 04 06 08 10
03 06 09 12 15
04 08 12 16 20
05 10 15 20 25
和为 10 的子矩形有:
一、01 02 03 04
二、
01
02
03
04
三、04 06
四、
04
06
五、10
六、10
以上共六个。
Data Constraint
对 10%的输入数据:size(s)≤10
对30%的输入数据:size(s)≤100
对100%的输入数据:0 ≤a≤1000000000,size(s)≤4000
赛时
思想ac,然后oj运行坑人,之后数组太小,0没特判等等。。。。。。0分
正解
都说思想ac了,对于每个矩阵从i,j(左上角)到x,y(右下角),它的值其实就是(s[x]-s[i-1])*(s[y]-s[j-1]),s为前缀和。那么如果一个矩阵的答案是a的话,(s[x]-s[i-1])与(s[y]-s[j-1])都应该是a的约数,于是我们用个桶装一下可能的s值的个数,然后就找a的两个约数,当这两个约数不一样时,ans就加上这两个约数的个数的乘积再乘2,如果一样的话,就不乘2。最后a=0时需特判,答案就是s值为0时,其他数可以任意取,也就是bz[0](0的数量) *其他数的数量,而其他数的数量其实是(len+1)*len/2也就是等差数列。最后还要减去bz[0]*bz[0],至于为什么,其实同理上面约数相等时要不用乘2,那么这里也就是减去多的。
代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
int a,cnt,s[40007],ans,bz[10000000];
int main(){
scanf("%d",&a);
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){
s[++cnt]=ch-'0';
ch=getchar();
}
for(int i=1;i<=cnt;i++)
s[i]+=s[i-1];
for(int i=1;i<=cnt;i++)
for(int j=i;j<=cnt;j++)
bz[s[j]-s[i-1]]++;
for(int i=2;i<=trunc(sqrt(a));i++)
if(a%i==0)
if(bz[i]&&bz[a/i]){
if(i!=a/i) ans+=bz[i]*bz[a/i]*2;
else ans+=bz[i]*bz[a/i];
}
if(a==0){
for(int i=1;i<=s[cnt];i++)
ans+=bz[i];
ans*=bz[0]*2;
ans+=bz[0]*bz[0];
}
printf("%d\n",ans);
}