CF1060H Sophisticated Device【构造】

给定正整数 \(d\) 和质数 \(p\),用至多 \(4999\) 次模 \(p\) 意义下加法、\(d\) 次幂实现模 \(p\) 意义下乘法。

\(2\le d\le 10\),\(d<p\le 10^9+9\)。


考虑到 \(xy=((x+y)^2-x^2-y^2)/2\),也就是说在 \(d=2\) 的时候我们实现减法、乘常数就做完了,都可以用龟速乘实现。

至于平方咋办呢?实际上可以构造 \(a_0,a_1,\cdots,a_d\) 满足 \(x^2=\sum_{i=0}^da_i(x+i)^d=\sum_{i=0}^d\binom dix^{d-i}\sum_{j=0}^dj^ia_j\),用个 Gauss 消元解方程即可。

操作次数大概 \(O(d\log p)\),常数不会算。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int d, mod, A[12][12];
void qmo(int &x){x += x >> 31 & mod;}
int ksm(int a, int b){
	int r = 1;
	for(;b;b >>= 1, a = (LL)a * a % mod)
		if(b & 1) r = (LL)r * a % mod;
	return r;
}
void Gauss(int n){
	for(int i = 0;i < n;++ i){
		if(!A[i][i])
			for(int j = i+1;j < n;++ j)
				if(A[j][i]){swap(A[i], A[j]); break;}
		int tmp = ksm(A[i][i], mod-2);
		for(int j = i;j <= n;++ j) A[i][j] = (LL)A[i][j] * tmp % mod;
		for(int j = 0;j < n;++ j) if(j != i)
			for(int k = i+1;k <= n;++ k)
				qmo(A[j][k] -= (LL)A[j][i] * A[i][k] % mod);
	}
}
void mul(int a, int b, int c){
	printf("+ 1001 1001 %d\n", c);
	printf("+ %d 1001 1002\n", a);
	for(;b;b >>= 1){
		if(b & 1) printf("+ %d 1002 %d\n", c, c);
		puts("+ 1002 1002 1002");
	}
}
void sub(int a, int b, int c){
	mul(b, mod-1, 1003);
	printf("+ %d 1003 %d\n", a, c);
}
void pw2(int a, int b){
	printf("+ 1001 1001 %d\n", b);
	printf("+ %d 1001 1004\n", a);
	for(int i = 0;i <= d;++ i){
		puts("^ 1004 1005");
		mul(1005, A[i][d+1], 1006);
		printf("+ %d 1006 %d\n", b, b);
		if(i < d) puts("+ 1004 1007 1004");
	}
}
int main(){
	scanf("%d%d", &d, &mod);
	for(int i = 0;i <= d;++ i)
		for(int j = 0;j <= d;++ j)
			A[i][j] = ksm(j, d-i);
	A[2][d+1] = ksm(d*(d-1ll)>>1, mod-2);
	Gauss(d+1);
	for(int i = mod-1;i;i >>= 1){
		if(i & 1) puts("+ 1000 1001 1001");
		puts("+ 1000 1000 1000");
	}
	puts("+ 1 2 3");
	pw2(1, 4); pw2(2, 5); pw2(3, 6);
	puts("+ 4 5 7");
	sub(6, 7, 8);
	mul(8, mod+1>>1, 9);
	puts("f 9");
}
上一篇:Hbase常用表操作


下一篇:PAT乙级1001 用C语言进行编程