// by Gospel_rock #include<bits/stdc++.h> #define all(vec) vec.begin(),vec.end() #define PB push_back #define EB emplace_back #define EM emplace #define FI first #define SE second #define pct __builtin_popcountll #define ctz __builtin_ctzll #define SZ(a) ((long long) a.size()) #define FOR(i, a, b) for (long long i = (a); i <= (b); ++i) #define ROF(i, a, b) for (long long i = (a); i >= (b); --i) #define debug(var) cerr << #var <<":"<<var<<"\n"; #define cend cerr<<"\n-----------\n" #define lson(var) (var<<1) #define rson(var) (var<<1|1) #define fsp(x) fixed<<setprecision(x) #define minn(vec) *min_element(vec.begin(),vec.end()) #define maxx(vec) *max_element(vec.begin(),vec.end()) usingnamespace std; #ifdef LOCAL template<typename T> void _print(T x) { cerr << x; } // 可以打印多层数组,但是格式不是很好 template<typename T> void _print(vector<T> v) { cerr << "[ "; for (T i : v) _print(i), cerr << " "; cerr << "]"; } template<typename T> void _print(set<T> s) { cerr << "{ "; for (T i : s) _print(i), cerr << " "; cerr << "}"; } template<typename T, typename U> void _print(pair<T, U> p) { cerr << "{"; _print(p.first); cerr << ", "; _print(p.second); cerr << "}"; } template<typename T, typename U> void _print(map<T, U> m) { cerr << "{ "; for (auto &p : m) _print(p), cerr << " "; cerr << "}"; } // 打印两层数组,格式好一些 template<typename T> void _print(vector<vector<T>> v){cerr<<"{\n";for (auto i : v) _print(i), cerr << "\n";cerr<<" }";} #endif
using ll = longlong;using ull = unsignedlonglong; using DB=double;using LD=longdouble; using i128 = __int128; using pdd = pair<DB,DB>;using plb = pair<ll,bool>; using pll = pair<ll,ll>;using vll=vector<ll>;using vb=vector<bool>; using tll = tuple<ll,ll,ll>;using vii=vector<int>; using vpll = vector<pll>;using vtll = vector<tll>; using vdb = vector<DB>;using vc=vector<char>; using arr3 = array<ll,3> ;using arr2 = array<ll,2>; using CD=complex<double>; staticconstexpr ll MAXN=(ll)1e6+10,INF=(ll)1e17+3; // 1e17+3是素数 1e18+9是素数 staticconstexpr ll mod=(ll)1e9+7; // 998244353; staticconstexprdouble eps=1e-8;constdouble pi=acos(-1.0); ll N,M,Q,X,K,T,lT;
inlinevoid __(); signedmain() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); cin>>lT; while(lT--) __(); return0; } /* */ // https://threadsiiithyderabad.quora.com/Tutorial-on-Trie-and-example-problems // AC https://judge.yosupo.jp/submission/308823 test min_xor erase insert 有0 // AC https://codeforces.com/contest/706/submission/334623853 test arg_max max // AC https://www.codechef.com/viewsolution/1183578991 综合运用 有0 structXORTrie { int B; // 最高位(含) structNode { int nxt[2]; int cnt; // 经过该节点的数的个数(叶子 = 出现次数) Node() { nxt[0] = nxt[1] = -1; cnt = 0; } }; vector<Node> tr; explicitXORTrie(int max_bit = 63) : B(max_bit) { tr.reserve(1 << 20); tr.emplace_back(); // root } voidclear(){ tr.clear(); tr.emplace_back(); } inlinevoidinsert(unsignedlonglong x){ int u = 0; for (int b = B; b >= 0; --b) { int bit = int((x >> b) & 1ull); if (tr[u].nxt[bit] == -1) { tr[u].nxt[bit] = (int)tr.size(); tr.emplace_back(); } u = tr[u].nxt[bit]; ++tr[u].cnt; } } inlineintcount(unsignedlonglong x)const{ int u = 0; for (int b = B; b >= 0; --b) { int bit = int((x >> b) & 1ull); int v = tr[u].nxt[bit]; if (v == -1) return0; u = v; } return tr[u].cnt; } inlineboolerase(unsignedlonglong x){ if (tr.size() == 1) returnfalse; staticint pathBit[70]; int u = 0, depth = 0; for (int b = B; b >= 0; --b) { int bit = int((x >> b) & 1ull); int v = tr[u].nxt[bit]; if (v == -1 || tr[v].cnt == 0) returnfalse; pathBit[depth++] = bit; u = v; } if (tr[u].cnt == 0) returnfalse; u = 0; for (int i = 0; i < depth; ++i) { int bit = pathBit[i]; int v = tr[u].nxt[bit]; --tr[v].cnt; if (tr[v].cnt == 0) tr[u].nxt[bit] = -1; // 懒回收 u = v; } returntrue; } inlineunsignedlonglongmax_xor(unsignedlonglong x)const{ if (tr.size() == 1) return0ull; int u = 0; unsignedlonglong ans = 0; for (int b = B; b >= 0; --b) { int bit = int((x >> b) & 1ull); int prefer = tr[u].nxt[bit ^ 1]; int same = tr[u].nxt[bit]; if (prefer != -1 && tr[prefer].cnt > 0) { u = prefer; ans |= (1ull << b); } else { u = same; // 至少有一条有效路 } } return ans; } inlineunsignedlonglongmin_xor(unsignedlonglong x)const{ if (tr.size() == 1) return0ull; // empty int u = 0; unsignedlonglong ans = 0; for (int b = B; b >= 0; --b) { int bit = int((x >> b) & 1ull); int same = tr[u].nxt[bit]; int other = tr[u].nxt[bit ^ 1]; if (same != -1 && tr[same].cnt > 0) { u = same; } else { u = other; ans |= (1ull << b); } } return ans; } inlineunsignedlonglongargmax_xor(unsignedlonglong y)const{ if (tr.size() == 1) return0ull; int u = 0; unsignedlonglong chosen = 0; for (int b = B; b >= 0; --b) { int bit = int((y >> b) & 1ull); int prefer = tr[u].nxt[bit ^ 1]; int same = tr[u].nxt[bit]; if (prefer != -1 && tr[prefer].cnt > 0) { u = prefer; chosen |= (unsignedlonglong)(bit ^ 1) << b; } else { u = same; chosen |= (unsignedlonglong)bit << b; } } return chosen; } inlineunsignedlonglongargmin_xor(unsignedlonglong x)const{ if (tr.size() == 1) return0ull; // 空集时随便返 0 int u = 0; unsignedlonglong chosen = 0; for (int b = B; b >= 0; --b) { int bit = int((x >> b) & 1ull); int same = tr[u].nxt[bit]; int other = tr[u].nxt[bit ^ 1]; if (same != -1 && tr[same].cnt > 0) { u = same; // 让该位 XOR=0 if (bit) chosen |= (1ull << b); // chosen 的该位 = bit } else { u = other; // 只能走相反位,该位 XOR=1 if (bit ^ 1) chosen |= (1ull << b); // chosen 的该位 = bit^1 } } return chosen; } }tr; // 处理无符号数
OK 啊,偷偷看了一眼题解,这个题解写的还是可以的。比这垃圾 AI 提示写的好。这 AI 提示,我告诉他我的思路,我干脆比不告诉他我的思路还好,写的还好一点。这真的纯纯傻逼,还不如不写。
M 等于一的情况,一种比较方便的实现方法呢,就是直接选择一个极长段,这个极长段中的所有数都比最大值小。不断地选择这样的极长段进行操作,记录一下找不到这个这样子的极长段所需要的操作数量。说白了,这个做法就是一个贪心。
M = 2 的时候的错误解法(不过,这里面他这个段内逻辑求解写的还是非常好的,要可以参考参考。嗯,不是可以参考一下,是非常好,要参考)(这里面也有一些我画的图,因为前面我以为这个做法是正确的,不过呢,现在是现在发现是错的)
现在问题在于 M 等于2的情况下,另外一个值怎样取?但是你会发现,其实这道题目它的值域非常小啊,另外一个值怎样取?你不知道怎样取,你直接枚举就行了,一共就100个值,它总归是变成比最大值小的值,是吧?
OK 啊,我已经想到了一种可以解决 M 等于2的情况下的 DP 的方法。
不过这个方法目前的瓶颈在于,就是说从转移过来的位置到我的这个 pos 之间,这一段的求解,如果使用贪心法有点慢了。
我们现在的问题如下: 对于段[l,r],把它所有元素变成max(a[l..r])所需的最小操作数,如何快速预处理?
(对于任意目标值 T=max(a[l..r])+k,代价只比 T=max 时多 k,而目标值 T 又不可能比 Max A 从 L 到 R 还小,这是不可能的。)
进一步追问公式细节(**讲的非常清楚非常清楚,好好看仔细看**。)
好,从头推。
第一步:最少操作次数的一般公式
操作是"选一个连续区间,全体 +1"。目标是把 a 变成 b(bi≥ai)。
令 di=bi−ai,即每个位置还需要增加的量。问题变成:用最少次"选连续区间全体 -1"操作,把d清零。
从左到右看 d 数组: