Pythagoras HDU - 6211
Given a list of integers a0,a1,a2,⋯,a2k−1. Pythagoras triples over 109 are all solutions of x2+y2=z2 where x,y and z are constrained to be positive integers less than or equal to 109. You are to compute the sum of ay mod 2k of triples (x,y,z) such that
and they are relatively prime, i.e., have no common divisor larger than 1
.
Input
The first line is an integer T (1≤T≤3) indicating the total number of cases.
For each test case the first line is the integer k (1≤k≤17).
The second line contains 2k integers corresponding to a0 to a2k−1, where each ai satisfies 1≤ai≤255
.
Output
For each case output the sum of ay mod 2k
in a line.
Sample Input
3
2
0 0 0 1
2
1 0 0 0
2
1 1 1 1
Sample Output
39788763
79577506
159154994
题意:
给出 ,求出所有满足 问 是多少
分析:
这题是个很迷的题,各种神奇
首先学习到了对于取模2的幂次来说,可以进行交换(我没找到相关定理,只是根据题解推出来的,要不然这题不可能对),什么意思呢,就是比如一个数 ,计算 ,如果 ,那么 ,举个具体的例子来说
这个结论貌似只对取模2的幂有效,对于一般数的取模是肯定不对的(我没找到相关定理解释,但是猜测是对的,因为这道题对了,我也是看着他们的题解)
下面先说一下这道题,很明显我们需要得到1e9内的本原勾股数组,并且我们知道本原勾股数组公式为:
且 互质, 有一奇一偶,即 是奇数
维基百科原话这样说:
Euclid’s formula[3] is a fundamental formula for generating Pythagorean triples given an arbitrary pair of integers m and n with m > n > 0. The formula states that the integers
form a Pythagorean triple. The triple generated by Euclid’s formula is primitive if and only if m and n are coprime and not both odd. When both m and n are odd, then a, b, and c will be even, and the triple will not be primitive; however, dividing a, b, and c by 2 will yield a primitive triple when m and n are coprime and both odd.[4]
因此目标是枚举出互质的数对,然后判断m-n是奇数那么就找到了一个勾股数
枚举互质的数对这时有一个神奇的方法,就是法里数列,构造法里数列的方式以一个叫Stern-Brocot tree的东西,其实就是递归生成n阶的法里数列,法里数列有非常良好的性质,其中一个就是得到的分数分子分母都是互质的,而且是全部的n内的互质对构成的真分数(具体关于法里数列的内容去网上找吧我这里有有个法里数列csdn,可能不全,可以看看维基百科),这样就能得到n内互质数对,然后判断就能得到本原勾股数组
根据上面我们说的取模2的幂次的性质,因为y大小会达到接近1e9的规模,而每次取模最大 ,所以预处理的时候就直接取模 好了,然后这样预处理出每个y取模后对应下标出现了几次
在得到每个数列a的时候,遍历1到 ,看每个y的贡献次数,然后在乘上这个实际取模 下标的那个a数列中的值,求和即可
而且这里取模是用位运算做的,结论取模2的幂次的数,相当于和这个数-1按位与即
=
&
最后一个神奇的地方,网上有人说法里数列Stern-Brocot tree构造的时间复杂度是 的,不知道怎么算,感觉这个复杂度恨不能理解,怎么不超时呢?我用clcok计算了一下时间花费发现1e5的时候0ms,1e8的时候500多毫秒,1e9的时候就栈溢出了,所以本地跑不出来,你也测不了样例,提交就是过,测评姬真强,哈 哈。。。
code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1 << 17;
const int MAX = 1e9;
int k;
int a[maxn+50];
int ans[maxn+50];
void solve(int l1,int r1,int l2,int r2){
int ml = (l1 + l2);
int mr = (r1 + r2);
if((ll)ml * ml + (ll)mr * mr > MAX) return;
if((mr - ml) & 1){
ans[max(mr*mr-ml*ml,2*ml*mr)&(maxn-1)]++;
}
solve(l1,r1,ml,mr);
solve(ml,mr,l2,r2);
}
int main(){
int T;
scanf("%d",&T);
solve(0,1,1,1);
while(T--){
scanf("%d",&k);
for(int i = 0; i < (1 << k); i++){
scanf("%d",&a[i]);
}
ll sum = 0;
for(int i = 0; i < maxn; i++){
sum += (ll)ans[i] * a[i&(1<<k)-1];
}
printf("%lld\n",sum);
}
return 0;
}
此外这题还以一种方法来求本原勾股数组,真是打开眼界
利用这个数来生成Tree of primitive Pythagorean triples
也是递归,其实就是给了三个矩阵,每个本原勾股数组乘这三个 矩阵都会生成三个新的本原勾股数组,而且这样递归下去不会重复,那么让根节点为(3,4,5),一直往下递归求即可,其实就是个三叉树,当然了本地必然还是跑不出来的,别想了1e9呢
#include<bits/stdc++.h>
using namespace std;
const int LMT = 1e9;
long long cnt = 0;
const int N = 1<<17;
const int MOD = N - 1;
int dig[N], a[N], T, k;
//核心算法
void solve(long long a, long long b, long long c)
{
if(c > LMT) return;
dig[ max(a, b)&MOD ] ++;
long long aa = a<<1;
long long bb = b<<1;
long long cc = c<<1;
solve(a-bb+cc, aa-b+cc, aa-bb+cc+c);
//solve(a-(b<<1)+(c<<1), (a<<1)-b+(c<<1), (a<<1)-(b<<1)+(c<<1)+c);
solve(a+bb+cc, aa+b+cc, aa+bb+cc+c);
//solve(a+(b<<1)+(c<<1), (a<<1)+b+(c<<1), (a<<1)+(b<<1)+(c<<1)+c);
solve(bb+cc-a, b+cc-aa, bb+cc+c-aa);
//solve(-a+(b<<1)+(c<<1), -(a<<1)+b+(c<<1), -(a<<1)+(b<<1)+(c<<1)+c);
}
int main()
{
solve(3, 4, 5);
scanf("%d", &T);
while(T-- && scanf("%d", &k)!=EOF)
{
int mod = (1<<k);
for(int i=0;i<mod;i++)
scanf("%d", &a[i]);
long long ans = 0;
for(int i=0, j=0;i<N;i++,j++)
{
if(j == mod) j = 0;
ans += dig[i] * a[j];
}
printf("%lld\n", ans);
}
}