【学习笔记】[AGC047] Product Simulation

给你两种操作: a k ← a i + a j a_k\gets a_i+a_j akai+aj a k ← [ a i < a j ] a_k\gets [a_iak[ai<aj] ,让你用上述操作构造运算 A × B A\times B A×B A A A, B B B未知。

sol:思维题。首先我们要知道目的是用上述两种简单运算构造出比较复杂度情况,这里有一个引理:

1.1 1.1 1.1 A , B ∈ { 0 , 1 } A,B\in \{0,1\} A,B{0,1},那么 A × B = [ 1 < A + B ] A\times B=[1A×B=[1<A+B]

这条引理告诉我们如何构造最为基本的乘法运算。

让我们想想。什么样的数只有 0 / 1 0/1 0/1 ?显然 数的二进制表示

考虑一般情况。设 A = ( a n a n − 1 . . . a 0 ) 2 A=(a_na_{n-1}...a_0)_2 A=(anan1...a0)2 B = ( b m b m − 1 . . . b 0 ) 2 B=(b_mb_{m-1}...b_0)_2 B=(bmbm1...b0)2,那么 A × B = ∑ i = 0 n ∑ j = 0 m ( a i b j ) i + j A\times B=\sum_{i=0}^n\sum_{j=0}^m(a_ib_j)^{i+j} A×B=i=0nj=0m(aibj)i+j 。而我们知道 x 2 i x2^i x2i可以通过将 x x x自我复制 i i i次得到,因此我们只需将 A A A, B B B二进制拆分即可。

如何拆分?我们从高到低位考虑,最高位等价于 [ A ≥ 2 k ] [A\ge 2^k] [A2k],对于低位只需抵消高位的影响即可。(在式子右边加上之前分出来的高位)以此类推,可以递推的把每一位求出来。

总序列长度 O ( log ⁡ 3 n ) O(\log^3 n) O(log3n)

#include
#define ll long long
#define fi first
#define se second
#define pb push_back
using namespace std;
int A,B,tot=4;
struct node{
	int op,a,b,c;
};
vector<node>v;
void add(int x,int y,int z){v.pb({0,y,z,x});}
void get(int x,int y,int z){v.pb({1,y,z,x});} 
int mul(int x,int y){
	add(++tot,x,y),get(tot+1,3,tot),tot++;
	return tot;
} 
int fac(int x,int y){
	if(y==0)return x;
	add(++tot,x,x),y--;
	for(int i=0;i<y;i++)add(tot+1,tot,tot),tot++;
	return tot;
}
vector<int>div(int A){
	vector<int>v;int lst=++tot;//之前的和
	add(++tot,A,3);int l=tot;
	for(int i=29;i>=0;i--){
		int x=fac(3,i);add(++tot,x,lst);get(tot+1,tot,l),tot++;v.pb(tot);
		add(++tot,lst,fac(tot,i)),lst=tot;
	}reverse(v.begin(),v.end());return v;
}
int main(){
	cin.tie(0),cout.tie(0);
	ios::sync_with_stdio(false);add(4,0,1),get(3,3,4);
	vector<int>v1=div(0),v2=div(1);
	for(int i=0;i<v1.size();i++){
		for(int j=0;j<v2.size();j++){
			add(2,2,fac(mul(v1[i],v2[j]),i+j));
		}
	}
	cout<<v.size()<<"\n";
	for(auto x:v){
		cout<<(x.op?'<':'+')<<' '<<x.a<<' '<<x.b<<' '<<x.c<<"\n";
	}
}

你可能感兴趣的:(学习)