给定正整数 (d) 和质数 (p),用至多 (4999) 次模 (p) 意义下加法、(d) 次幂实现模 (p) 意义下乘法。
(2le dle 10),(d<ple 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}^dinom dix^{d-i}sum_{j=0}^dj^ia_j),用个 Gauss 消元解方程即可。
操作次数大概 (O(dlog 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
", c);
printf("+ %d 1001 1002
", a);
for(;b;b >>= 1){
if(b & 1) printf("+ %d 1002 %d
", c, c);
puts("+ 1002 1002 1002");
}
}
void sub(int a, int b, int c){
mul(b, mod-1, 1003);
printf("+ %d 1003 %d
", a, c);
}
void pw2(int a, int b){
printf("+ 1001 1001 %d
", b);
printf("+ %d 1001 1004
", a);
for(int i = 0;i <= d;++ i){
puts("^ 1004 1005");
mul(1005, A[i][d+1], 1006);
printf("+ %d 1006 %d
", 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");
}