bzoj3957
Posted 123456
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj3957相关的知识,希望对你有一定的参考价值。
数学+模拟
细节很多
首先我们发现,如果两个区间已经包含,那么可以输出empty,一个数能通过变换得到另一个区间的数,这个区间的大小必须小于等于终点区间的大小。加法不会改变区间大小,只有乘法会改变,而且每次乘法会使区间大小扩大m倍。其实我们发现,最终一个数会变成p*x+y,x是m的几次幂,y是一个a乘上一些m的幂再加上一些a.x=m^l+a(A0*m^l+A1*m^n-1+...+An)所以我们就是要把后面的东西展开。
但是题目要求操作数最少且字典序最小。所以我们要枚举最大的次数,枚举次数时还要保证次数最少。保证次数最少应该更多用乘法保证,所以就是把一些加法换成乘法,也应该尽量用高次代替低次,所以我们每次枚举次数,然后枚举每位,把每位用尽量大的数替代,后面的数清零,然后判断。字典序的判断比较鬼畜。
当m=0或m=1时把m赋成极大值,这样就可以保证m不会乘,impossible就是先把ans变成一个极大值,然后判断。
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<ll, char> PII; vector<PII> ans; ll a, m, p, q, r, s; int kase; bool cp(vector<PII> &A, vector<PII> &B) { ll s1 = 0, s2 = 0; for(int i = 0; i < A.size(); ++i) s1 += A[i].first; for(int i = 0; i < B.size(); ++i) s2 += B[i].first; // printf("%d %d\n", A.size(), B.size()); if(s1 != s2) return s1 < s2; int lim = min(A.size(), B.size()); for(int i = 0; i < lim; ++i) { if(A[i].second != B[i].second) return A[i].second < B[i].second; if(A[i].first != B[i].first) { if(A[i].second == ‘A‘) return A[i].first > B[i].first; else return A[i].first < B[i].first; } } return A.size() < B.size(); } void update(int x, ll target) { // printf("x=%d target=%d\n", x, target); vector<PII> v; v.clear(); for(int i = 0; i < x; ++i) { if(target % m) v.push_back(make_pair(target % m, ‘A‘)); target /= m; if(v.empty() || v.back().second == ‘A‘) v.push_back(make_pair(1ll, ‘M‘)); else ++v.back().first; } if(target) v.push_back(make_pair(target, ‘A‘)); reverse(v.begin(), v.end()); // for(int i = 0; i < v.size(); ++i) // printf(" %d%c", v[i].first, v[i].second); // printf("\n"); if(cp(v, ans)) swap(ans, v); } void process(int low, int high, int m, int t) { for(int i = 0, j = 1; i <= t; ++i, j *= m) { int x = (low + j - 1) / j * j; if(x > high) break; update(t, x); } } int main() { // freopen("output.txt", "w", stdout); while(scanf("%lld%lld%lld%lld%lld%lld", &a, &m, &p, &q, &r, &s)) { if(!a && !m && !p && !q && !s && !r) break; ans.clear(); if(m == 0 || m == 1) m = 1000000010ll; printf("Case %d:", ++kase); if(p >= r && q <= s) { printf(" empty\n"); continue; } ans.push_back(make_pair(2000000000ll, ‘A‘)); for(int mul = 0; q <= s && q - p <= s - r; ++mul, p *= m, q *= m) { ll minadd = max(0ll, (r - p + a - 1) / a), maxadd = (s - q) / a; if(minadd > maxadd) continue; process(minadd, maxadd, m, mul); //mul:最多乘mul次 } if(ans[0].first == 2000000000ll) { printf(" impossible\n"); continue; } for(int i = 0; i < ans.size(); ++i) printf(" %lld%c", ans[i].first, ans[i].second); printf("\n"); } // fclose(stdout); return 0; }
以上是关于bzoj3957的主要内容,如果未能解决你的问题,请参考以下文章