kmjp's blog

競技プログラミング参加記です

yukicoder : No.3278 Avoid Division

アイデア勝負な問題。
https://yukicoder.me/problems/no/3278

問題

整数変数x=0がある。また、素数Pがあったとする。Pは明に与えられない。
xに以下のクエリを計N個順次適用することを考える。

  • 各クエリは演算子と整数値A[i]を取る。演算子に応じて以下のいずれかを行う。
    • xにA[i]を加算し、Pで割ったあまりに置き換える。
    • xにA[i]を掛け、Pで割ったあまりに置き換える。
    • xをA[i]で割り、Pで割ったあまりに置き換える。

この結果と同じ処理を、加算・乗算をN回までと、除算を1回まで使い表現するプログラムを構築せよ。
このプログラムでは、Aの各値に加え、26個の整数変数を使える。

解法

割り算を1回でまとめるため、x=p/qと有理数の形で持とう。
そうすれば

  • xへのA[i]の加算は、p = (p + A[i]*q) % P とすればよい
  • xへのA[i]の乗算は、p = p*A[i] % P とすればよい
  • xへのA[i]の除算は、q = q*A[i] % P とすればよい

そして最後にpをqで割ればよい。

int N;
string op[101];
ll A[101];

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>N;
	FOR(i,N) {
		cin>>op[i+1]>>A[i+1];
	}
	vector<string> S;
	int di=0;
	
	for(i=1;i<=N;i++) {
		if(op[i]=="+") {
			if(di==0) {
				S.push_back("add a A[" + to_string(i) + "] a");
			}
			else {
				S.push_back("mul z A[" + to_string(i) + "] y");
				S.push_back("add a a z");
			}
		}
		if(op[i]=="*") {
			S.push_back("mul a A[" + to_string(i) + "] a");
		}
		if(op[i]=="/") {
			if(di==0) {
				S.push_back("add y A[" + to_string(i) + "] y");
				di=1;
			}
			else {
				S.push_back("mul y A[" + to_string(i) + "] y");
			}
		}
	}
	if(di) S.push_back("div a a y");
	cout<<S.size()<<endl;
	FORR(s,S) cout<<s<<endl;
}

まとめ

これどうやって解法チェックしてるんだろと思ったら、Pをランダム生成して値を比較してた。