dp[ i ] 表示分完前 i 段, 最多能分几段。
我们能得到一个n2的dp, 然后用字典树优化掉。
我用了一个multiset去维护删除, 但实际上因为dp值有单调性, 所有维护sz就够了。
换成c++卡内存卡过去的。
//#pragma GCC optimize(2) //#pragma GCC optimize(3) //#pragma GCC optimize(4) //#include<bits/stdc++.h> #include<cstdio> #include<algorithm> #include<set> #define LL long long #define LD long double #define ull unsigned long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ALL(x) (x).begin(), (x).end() #define fio ios::sync_with_stdio(false); cin.tie(0); using namespace std; const int N = 1e5 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 998244353; const double eps = 1e-8; const double PI = acos(-1); template<class T, class S> inline void add(T &a, S b) {a += b; if(a >= mod) a -= mod;} template<class T, class S> inline void sub(T &a, S b) {a -= b; if(a < 0) a += mod;} template<class T, class S> inline bool chkmax(T &a, S b) {return a < b ? a = b, true : false;} template<class T, class S> inline bool chkmin(T &a, S b) {return a > b ? a = b, true : false;} //mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); const int LOG = 28; int n, up, len; int a[N]; int dp[N]; void read() { int p, q; scanf("%d%d%d", &a[1], &p, &q); for(int i = 2; i <= n; i++) { a[i] = (1LL * a[i - 1] * p + q) % 268435456; } for(int i = 1; i <= n; i++) { a[i] ^= a[i - 1]; } } int trietot, Rt; struct Trie { int ch[2], mx; } tr[N * LOG]; multiset<int> mulset[N * LOG]; inline int newNode() { trietot++; tr[trietot].ch[0] = 0; tr[trietot].ch[1] = 0; tr[trietot].mx = -1; mulset[trietot].clear(); return trietot; } void ins(int x, int val) { int u = Rt; for(int i = LOG - 1; i >= 0; i--) { chkmax(tr[u].mx, val); int v = tr[u].ch[x >> i & 1]; if(!v) tr[u].ch[x >> i & 1] = newNode(); v = tr[u].ch[x >> i & 1]; u = v; } mulset[u].insert(val); chkmax(tr[u].mx, val); } void del(int u, int x, int val, int d) { if(d == -1) { mulset[u].erase(mulset[u].lower_bound(val)); if(SZ(mulset[u])) tr[u].mx = *mulset[u].rbegin(); else tr[u].mx = -1; return; } del(tr[u].ch[x >> d & 1], x, val, d - 1); tr[u].mx = max(tr[tr[u].ch[0]].mx, tr[tr[u].ch[1]].mx); } int query(int x) { int ans = -1; bool limit = true; bool ban = false; int u = Rt; for(int i = LOG - 1; i >= 0; i--) { if(limit) { int sml = x >> i & 1; int big = sml ^ 1; int smlv = tr[u].ch[sml]; int bigv = tr[u].ch[big]; if(!(up >> i & 1)) { u = smlv; } else { if(tr[smlv].mx >= tr[bigv].mx) { limit = false; u = smlv; } else { chkmax(ans, tr[smlv].mx); u = bigv; } } } else { chkmax(ans, tr[u].mx); ban = true; break; } } if(!ban) chkmax(ans, tr[u].mx); return ans; } void init() { tr[0].mx = -1; trietot = 0; Rt = newNode(); } int main() { int T; scanf("%d", &T); while(T--) { init(); scanf("%d%d%d", &n, &up, &len); read(); ins(0, 0); for(int i = 1, j = 0; i <= n; i++) { while(j + len < i) { if(dp[j] != -1) del(Rt, a[j], dp[j], LOG - 1); j++; } dp[i] = query(a[i]); if(dp[i] != -1) { dp[i]++; ins(a[i], dp[i]); } } if(dp[n] != -1) printf("%d ", dp[n]); else puts("0"); } return 0; } /* */