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");
}