【题解】CF1060H Sophisticated Device
自己博客的广告,若以后有修改多半只写在自己博客中。
题目链接
这道题实在是毒瘤。以及洛谷上的翻译其实是我翻的,质量跟机翻差不多。
首先我们确定求出
这个思路不难想到:我们能够比较容易实现的两个操作数的运算只有加、减,于是我们将运算转换为加、减与只有一个操作数的平方、除以 2。关键在于如何实现这些运算。
前置技能
-
快速幂/乘
-
高斯消元
-
exgcd 求乘法逆元
-
少量数学知识
-
大量耐心
我们先考虑几个简单的运算:
0
在求解过程中,有一个数字 0 是很方便的,利用 + zero zero x 就可以清空一格。
在这里需要用到快(慢?)速乘,实现:
int f=p-1;
while(f){
if(f&1ll){
cout<<"+ "<<4998<<" "<<zero<<" "<<zero<<endl;
}
cout<<"+ "<<4998<<" "<<4998<<" "<<4998<<endl;
f/=2;
}
//zero=4999
这样 zero 格就有了一个常数 0。
乘以常数
同样是快速乘。要注意的是,每次必须清空所需格子。
int getmulti(int a,int b,int q){
b=(b%p+p)%p;
int ans=(q?q:++tot);
int x=++tot;
while(b){
if(b&1ll){
cout<<"+ "<<x<<" "<<ans<<" "<<ans<<endl;
}
cout<<"+ "<<x<<" "<<x<<" "<<x<<endl;
b/=2;
}
return ans;
}
//如果有 q ,答案存在 q 当中。返回结果所在格子。
减法
int jian(int a,int b){
b=getmulti(b,p-1);
++tot;
cout<<"+ "<<a<<" "<<b<<" "<<tot<<endl;
return tot;
}
除以常数
即乘以其逆元。
下面是重头戏:
求一个数的平方
很明显,
我们考虑将
将它展开,再按
显然我们要求
c[1][1]=1;
for(int i=1;i<=d+1;i++){
for(int j=1;j<=i;j++){
if(i==1&&j==1)continue;
c[i][j]=c[i-1][j]+c[i-1][j-1];
}
}
for(int i=0;i<=d;i++){
int q=1;
for(int j=0;j<=d;j++){
a[j][i]=c[d+1][j+1]*q%p;
q*=i;
q%=p;
}
}
a[d-2][d+1]=1;
for(int i=0;i<=d;i++){
bool ok=false;
int j=0;
for(;j<=d;j++){
if(a[j][i]&&!u[j]){
ok=true;
u[j]=true;
break;
}
}
double orz=a[j][i];
for(int k=0;k<=d+1;k++){
a[j][k]*=getinv(orz,1,p);
a[j][k]%=p;
}
for(int k=0;k<=d;k++){
if(k==j)continue;
orz=a[k][i]*=getinv(a[j][i],1,p);
for(int l=0;l<=d+1;l++){
a[k][l]-=orz*a[j][l];
a[k][l]=(a[k][l]%p+p)%p;
}
}
}
实际求的时候,只需要用公式
int getpow2(int x){
int q=++tot;
cout<<"+ "<<x<<" "<<zero<<" "<<q<<endl;
int sum=++tot;
cout<<"+ "<<zero<<" "<<zero<<" "<<sum<<endl;
int po=++tot;
int mul=++tot;
for(int i=0;i<=d;i++){
cout<<"^ "<<q<<" "<<po<<endl;
getmulti(po,a[i][d+1],mul);
cout<<"+ "<<mul<<" "<<sum<<" "<<sum<<endl;
cout<<"+ "<<q<<" "<<4997<<" "<<q<<endl;
}
return sum;
}
最后就将这些 simple 的操作联合起来:
int x2=getpow2(1);
int y2=getpow2(2);
int q=jian(xysum2,x2);
jian(q,y2);
int ans=getmulti(tot,getinv(2,1,p));
cout<<"f "<<ans<<endl;
完整代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int getint(){
int ans=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
ans=ans*10+c-'0';
c=getchar();
}
return ans*f;
}
const int inf=19260817;
int extgcd(int a,int b,int& x,int& y){
if(b){
int r=extgcd(b,a%b,y,x);
y-=x*(a/b); return r;
} else { x=1; y=0; return a; }
}
int getinv(int a,int b,int M){
int x,y,r=extgcd(a,M,x,y);
if(b%r) return -1; else x=(x+M)%M*b/r;
return x%(M/r);
}
int tot=2,zero=4999;
int d,p;
int getinv(int x){
int inv=getinv(d,p-2,p);
++tot;
cout<<"^ "<<x<<" "<<tot<<endl;
for(int i=0;i<inv-1;i++){
cout<<"^ "<<tot<<" "<<tot<<endl;
}
return tot;
}
int a[20][20],c[20][20];
int getpow2(int x);
int getmulti(int a,int b,int q=0);
int jian(int a,int b);
int getpow2(int x){
int q=++tot;
cout<<"+ "<<x<<" "<<zero<<" "<<q<<endl;
int sum=++tot;
cout<<"+ "<<zero<<" "<<zero<<" "<<sum<<endl;
int po=++tot;
int mul=++tot;
for(int i=0;i<=d;i++){
cout<<"^ "<<q<<" "<<po<<endl;
getmulti(po,a[i][d+1],mul);
cout<<"+ "<<mul<<" "<<sum<<" "<<sum<<endl;
cout<<"+ "<<q<<" "<<4997<<" "<<q<<endl;
}
return sum;
}
int getmulti(int a,int b,int q){
b=(b%p+p)%p;
int ans=(q?q:++tot);
cout<<"+ "<<zero<<" "<<zero<<" "<<ans<<endl;
int x=++tot;
cout<<"+ "<<zero<<" "<<a<<" "<<x<<endl;
while(b){
if(b&1ll){
cout<<"+ "<<x<<" "<<ans<<" "<<ans<<endl;
}
cout<<"+ "<<x<<" "<<x<<" "<<x<<endl;
b/=2;
}
return ans;
}
int jian(int a,int b){
b=getmulti(b,p-1);
++tot;
cout<<"+ "<<a<<" "<<b<<" "<<tot<<endl;
return tot;
}
bool u[20];
signed main(){
d=getint(),p=getint();
c[1][1]=1;
for(int i=1;i<=d+1;i++){
for(int j=1;j<=i;j++){
if(i==1&&j==1)continue;
c[i][j]=c[i-1][j]+c[i-1][j-1];
}
}
for(int i=0;i<=d;i++){
int q=1;
for(int j=0;j<=d;j++){
a[j][i]=c[d+1][j+1]*q%p;
q*=i;
q%=p;
}
}
a[d-2][d+1]=1;
for(int i=0;i<=d;i++){
bool ok=false;
int j=0;
for(;j<=d;j++){
if(a[j][i]&&!u[j]){
ok=true;
u[j]=true;
break;
}
}
double orz=a[j][i];
for(int k=0;k<=d+1;k++){
a[j][k]*=getinv(orz,1,p);
a[j][k]%=p;
}
for(int k=0;k<=d;k++){
if(k==j)continue;
orz=a[k][i]*=getinv(a[j][i],1,p);
for(int l=0;l<=d+1;l++){
a[k][l]-=orz*a[j][l];
a[k][l]=(a[k][l]%p+p)%p;
}
}
}
int f=p-1;
while(f){
if(f&1ll){
cout<<"+ "<<4998<<" "<<zero<<" "<<zero<<endl;
}
cout<<"+ "<<4998<<" "<<4998<<" "<<4998<<endl;
f/=2;
}
cout<<"+ "<<1<<" "<<2<<" "<<(++tot)<<endl;
int xysum2=getpow2(tot);
int x2=getpow2(1);
int y2=getpow2(2);
int q=jian(xysum2,x2);
jian(q,y2);
int ans=getmulti(tot,getinv(2,1,p));
cout<<"f "<<ans<<endl;
return 0;
}