Matrix (round 213 div1)

You have a string of decimal digits s. Let's define bij = si·sj. Find in matrix b the number of such rectangles that the sum bij for all cells(i, j) that are the elements of the rectangle equals a in each rectangle.

A rectangle in a matrix is a group of four integers (x, y, z, t) (x ≤ y, z ≤ t). The elements of the rectangle are all cells (i, j) such that x ≤ i ≤ y, z ≤ j ≤ t.

Input

The first line contains integer a (0 ≤ a ≤ 109), the second line contains a string of decimal integers s (1 ≤ |s| ≤ 4000).

Output

Print a single integer — the answer to a problem.

Please, do not write the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cincout streams or the %I64dspecifier.

解题:

1) 明确目标,本题的目标是需要求得矩阵中矩形内元素之和等于a的矩形数量。

2) 矩形的形成,两行两竖即可生成。即下图所示:


3) 得到矩形内的元素之和,所有元素为 b(ac) …… b(ad); b(a+1 c)…… b(a+1 d); ……  ; b(b c)……b(b d);

由于b(ij) = si.sj ; 所以求得矩形内所有元素之和为S= [s(a) +s(a+1)……s(b)] [ s(c) + s(c+1)……s(d)]  ,可以看出S为两个连续字串之和的乘积;

设字符串为s,要求得S=a的个数,首先要求得连续字串之和,其次找到所有的和中满足乘积等于a的个数

4) 求解连续字串之和算法

k(c,d) = s(d) - s(c) ,其中s(d)表示前d个字符数字之和,k(c,d)表示[c,d]之间子串数字之和,即为所求;

而s(d) 可以表示为s(d-1)+s[d]-‘0’,通过递推可以得到每一个s(i)的值, 假设从1开始编号;

5) 通过求得所有连续字串之和,下一步可以得到任意间隔之和集合P(允许重复),然后求得该集合内两数乘积等于a的数的个数;

6)了解该集合的特征: 0<= p <= s(n)<=50000;采用标记是否存在的方法来验证改元素,用t[50001] 来记录任意间断之和的数量;

7) 计算,特例 a = 0; 则至少一个k(c,d)=0;则 ans = t[0]*t[0] + 2*sum*t[0] ,计算为,两个都为0,或者只有一个为0;其中sum为除t[0]外集合P(允许重复)数量;

8) 计算乘积等于a,

     1. 记录每个数出现的次数 t[i] 表示

     2. 判断如何a%i==0;记忆a/i<=s(n),则肯定集合中存在两个数相乘等于a,数量为 ans+= t[i] * t[a/i]

     很显然,这里要提前排除i=0的情况,因此需要先判断a?0,如果是,则先计算 ans+= t[0] * t[i](0<= i<= n)

9) 注意事项,由于s(n)<=50000,即由于codefirst中int 为16位有符号整数,表示的范围为:-32768 ~ 32767,导致如果用int s[50000] 将会导致溢出,因此需要用long(32) 或者 long long(64) 来表示。由于溢出,第12个例子一直没能够跑出来,这个需要注意。

#include <iostream>
#include <string>

using namespace std;

long long s1[4001];
long long  t1[50000];
int main() {
	
	long long a;
	cin>>a;
	string s;
	cin>>s;
	int len = s.length();
	long long i,j;
	for(i=0;i<len;i++){
		s1[i+1] = s1[i]+s[i]-'0'; // the continuous distance problem
	//	t1[s1[i+1]]++;
	}
	for(i=1;i<=len;i++) {
		for(j=0;j<i;j++){
			t1[s1[i]-s1[j]]++; // exist problem     s1[n] >= s1[j]-s1[i] >= 0
		}
	}
	long long ans=0;
	if(a==0) {
		for(i=0;i<=s1[len];i++) ans+=t1[0]*t1[i];  // the multiply result is zero
	}
	
	for(i=1;i<=s1[len];i++)  
	if((a%i==0)&&(a/i<=s1[len]))
		ans+=t1[i]*t1[a/i];


	cout<<ans<<endl;
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值