「CF1060H」Sophisticated Device 题解

题目简介

题目简介超出了笔者的表述能力范围,所以挂上codeforces洛谷的直达链接。

分析

感谢洛谷题解区破壁人五号T_E_I_O_大佬的博客提供思路和参考。

0x0.

一些前置定义:

tot:已用的格子总数。

mod:即原题目中的\(p\)

z:数字 \(0\) 的所在位置,默认为 \(5000\),可以看做 \(p\)\(1\) 相加再\(\mod p\),实现参考某速乘:

inline int init(int a,int b,int p=0){
	if(!p)p=++tot;
	while(b){
		if(b&1)print_plus(a,p,p);
		b>>=1;
		print_plus(a,a,a);
	}
	return p;
}
z=init(4999,mod-1,5000);

print_plus():输出加法:

inline int print_plus(int a,int b,int c){std::cout<<"+ "<<a<<' '<<b<<' '<<c<<'\n';return c;}

print_power():输出幂运算:

inline int print_power(int a,int b){std::cout<<"^ "<<a<<' '<<b<<'\n';return b;}

clear():将某个格子赋值为 \(0\)

inline int clear(int p=0){if(!p)p=++tot;return print_plus(z,z,p);}

copy():将一个格子的值赋给另一个格子:

inline int copy(int x,int p=0){if(!p)p=++tot;return print_plus(z,x,p);}

0x1.

\(d=2\) 时,很容易想到,\(xy=\frac{(x+y)^2-x^2-y^2}{2}\) (初中知识)。

其中有减法和除法,考虑如何实现。

一致看向取模

0x2.

先讲乘法

\[x\times y=\sum_{i=1}^{x}y \]

可以考虑某速乘的方法:

inline int multi(int a,int b,int p=0){
	p=clear(p);
	int x=copy(a);
	return init(x,b%mod,p);
}

0x3.

对于减法,考虑\(a-b\equiv a+(p-1)b\ (mod\ p)\)

inline int minu(int a,int b){return print_plus(a,multi(b,mod-1),++tot);}

0x4

对于除法,即乘以其逆元

题目保证 \(p\),也就是本题解中的 \(mod\) 为一个质数,所以可以用费马小定理求其逆元:

inline ll quickly_power(ll a,int b){
	ll ans=1;
	while(b){
		if(b&1)ans=(ans*a)%mod;
		b>>=1;
		a=(a*a)%mod;
	}
	return ans;
}

0x5

这是本题中最重要,最难理解的一步。

\[x^2=\sum_{i=0}^{d}[a_i\times(x+i)^d]=a_0\times(x+0)^d+a_1\times(x+1)^d+\dots+a_d\times(x+d)^d \]

耐心地将其展开,可以得到:

\[x^2=\sum_{i=0}^{d}[C_{d}^{i}\sum_{j=0}^d(a_i\times j^i)\times x^{d-i}] \]

\[x^2=C_{d}^{0}(a_0+a_1+\dots+a_d)\times x^d+C_{d}^{1}(a_0\times 0^1+a_1\times 1^1+\dots+a_d\times d^1)\times x^{d-1}\dots C_{d}^{d}(a_0\times 0^d+a_1\times 1^d+\dots+a_d\times d^d)\times x^0 \]

要使这个式子成立,只需满足:

\[C_{d}^{0}(a_0+a_1+\dots+a_d)\times x^d=0 \]

\[C_{d}^{1}(a_0\times 0^1+a_1\times 1^1+\dots+a_d\times d^1)\times x^d=0 \]

\[\dots \]

\[C_{d}^{d-2}(a_0\times 0^{d-2}+a_1\times 1^{d-2}+\dots+a_d\times d^{d-2})\times x^2=1 \]

\[\dots \]

\[C_{d}^{d}(a_0\times 0^d+a_1\times 1^d+\dots+a_d\times d^d)\times x^0=0 \]

已知前面那项 \(C\neq 0\)\(x^k\) 未知。

所以:

\[a_0+a_1+\dots+a_d=0 \]

\[a_0\times 0^1+a_1\times 1^1+\dots+a_d\times d^1=0 \]

\[\dots \]

\[C_{d}^{d-2}(a_0\times 0^{d-2}+a_1\times 1^{d-2}+\dots+a_d\times d^{d-2})=1 \]

\[\dots \]

\[a_0\times 0^d+a_1\times 1^d+\dots+a_d\times d^d=0 \]

高斯消元即可

\(AC\ Code\)

#include<cstdio>
#include<iostream>
#include<functional>
typedef long long ll;
int tot=3,z;
ll mod;
inline int print_plus(int a,int b,int c){std::cout<<"+ "<<a<<' '<<b<<' '<<c<<'\n';return c;}
inline int print_power(int a,int b){std::cout<<"^ "<<a<<' '<<b<<'\n';return b;}
inline int clear(int p=0){if(!p)p=++tot;return print_plus(z,z,p);}
inline int copy(int x,int p=0){if(!p)p=++tot;return print_plus(z,x,p);}
inline ll quickly_power(ll a,int b){
	ll ans=1;
	while(b){
		if(b&1)ans=(ans*a)%mod;
		b>>=1;
		a=(a*a)%mod;
	}
	return ans;
}
inline int init(int a,int b,int p=0){
	if(!p)p=++tot;
	while(b){
		if(b&1)print_plus(a,p,p);
		b>>=1;
		print_plus(a,a,a);
	}
	return p;
}
inline int multi(int a,int b,int p=0){
	p=clear(p);
	int x=copy(a);
	return init(x,b%mod,p);
}
inline int minu(int a,int b){return print_plus(a,multi(b,mod-1),++tot);}
ll a[12][12];
ll c[12];
void Gauss(int d){
	for(int i=0;i<=d;++i)
		for(int j=0;j<=d;++j){
			a[i][j]=quickly_power(j,i);
            if(i==d-2)a[i][j]=(a[i][j]*d*(d-1)>>1)%mod;
		}
	a[d-2][d+1]=1;
	for(int i=0;i<=d;++i){
		for(int j=i;j<=d;++j)
			if(a[j][i]){std::swap(a[i],a[j]);break;}
		ll tmp=quickly_power(a[i][i],mod-2);
		for(int j=0;j<=d;++j){
			if(i==j)continue;
			long double b=a[j][i]*tmp%mod;
			for(int k=0;k<=d+1;++k){
				a[j][k]-=a[i][k]*b;
				a[j][k]=(a[j][k]%mod+mod)%mod;
			}
		}
	}
	for(int i=0;i<=d;++i)c[i]=a[i][d+1]*quickly_power(a[i][i],mod-2)%mod;
}
inline int power(int p,int d){
	int x=copy(p),y=clear(),ans=clear();
	for(int i=0;i<=d;++i){
		print_plus(x,y,++tot);
		print_power(tot,tot+1);++tot;
		int tmp=multi(tot,c[i]);
		print_plus(tmp,ans,ans);
		print_plus(4998,y,y);
	}
	return ans;
}
int main(){
	int d;std::cin>>d>>mod;
	print_plus(1,2,3);
	z=init(4999,mod-1,5000);
	Gauss(d);
	int x=power(1,d),y=power(2,d);
	int z=power(3,d);
	printf("f %d\n",multi(minu(minu(z,x),y),quickly_power(2,mod-2)));
	return 0;
}

$$-----EOF-----$$

posted @ 2022-04-03 21:54  AlienCollapsar  阅读(58)  评论(0)    收藏  举报
// 生成目录索引列表 // ref: http://www.cnblogs.com/wangqiguo/p/4355032.html // modified by: zzq