前言:CSP-S 模拟 19/11/12_#define 你骄傲个屁!
考前打击一次也挺好的!
反思一下今天犯的错误


T1:

cs int N = 1e6 + 5, M = 1e7 + 5;
int n, ch[M][26], ed[M], id[N], ct, node;

抱歉你已经凉了
写之前为什么没有算空间?
写之后为什么没有算空间?
检查的时候为什么没有算空间?
另外可以用 CSP-S 模拟 19/11/12_git_02 输出你的内存

cout << sizeof(ch) << '\n';

爆空间最划不来啊,CSP-S 模拟 19/11/12_git_03 至少还有分,但 CSP-S 模拟 19/11/12_i++_04 的话已经可以回去上文化课了!
考试的时候一定要格外注意


T2:
暴力和正解同时犯错!?
看来以后还有静态 CSP-S 模拟 19/11/12_git_05 一下两份都一样的 CSP-S 模拟 19/11/12_i++_06
然后还错了个细节
二分数组下标的时候可能比所有的都小,但是还是二分到了第一个

CSP-S 模拟 19/11/12_i++_07 做完题一大把时间来检查却没有静下心读一遍自己的代码


CSP-S 模拟 19/11/12_#define,你活该


CSP-S 模拟 19/11/12_git_09
想一想后缀数组的 CSP-S 模拟 19/11/12_i++_10 为什么要定义在 CSP-S 模拟 19/11/12_i++_11
就是因为把后缀排序过后可以满足题目的那个性质
CSP-S 模拟 19/11/12_git_12
所以 CSP-S 模拟 19/11/12_i++_13
所以把所有串按字典序排序就可以了
也可以用 CSP-S 模拟 19/11/12_i++_14 来理解,两个串的 CSP-S 模拟 19/11/12_i++_15 就是 CSP-S 模拟 19/11/12_i++_16 的深度,如果按 CSP-S 模拟 19/11/12_git_17 序来的话
可以满足两个的 CSP-S 模拟 19/11/12_i++_16 一定比中间夹着的点和它们的 CSP-S 模拟 19/11/12_i++_16
排序用 CSP-S 模拟 19/11/12_i++_20 就可以了
然后也可以用 CSP-S 模拟 19/11/12_i++_14 树来做,儿子用 CSP-S 模拟 19/11/12_i++_22
注意结点重复的情况,每个点开一个 CSP-S 模拟 19/11/12_i++_23 即可

#include<bits/stdc++.h>
#define cs const
using namespace std;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
return cnt * f;
}
cs int N = 1e6 + 5;
int n, id[N], ct, node;
int a[N], ps[N];
typedef pair<int,int> pi;
vector<pi> ans;
#define mp make_pair
string s[N];
bool cmp(int a, int b){ return s[a] < s[b] || (s[a] == s[b] && a < b);}
int main(){
n = read();
for(int i = 1; i <= n; i++){
cin >> s[i]; id[i] = i;
} sort(id + 1, id + n + 1, cmp);
for(int i = 1; i <= n; i++) ps[i] = a[i] = i;
for(int i = 1; i <= n; i++){
// 当前归位 id[i]
if(ps[id[i]] == i) continue;
ans.push_back(mp(i, ps[id[i]]));
ps[a[i]] = ps[id[i]];
swap(a[i], a[ps[id[i]]]);
} cout << ans.size() << '\n';
for(int i = 0; i < ans.size(); i++) cout << ans[i].first << " " << ans[i].second << '\n';
return 0;
}

CSP-S 模拟 19/11/12_i++_24
CSP-S 模拟 19/11/12_i++_25 排序后二分答案,假设当前高度是 CSP-S 模拟 19/11/12_git_26,那么最小次数就是把高度大于 CSP-S 模拟 19/11/12_git_26 的砍下去
CSP-S 模拟 19/11/12_i++_28
然后你发现这个东西没有办法变成 CSP-S 模拟 19/11/12_#define_29 之类的东西
但是发现 CSP-S 模拟 19/11/12_#define_30 的贡献是可以全部减掉的
可以多减 1 的就是 CSP-S 模拟 19/11/12_#define_31
发现就是统计一个后缀小于等于某个数的个数,主席树即可
复杂度 CSP-S 模拟 19/11/12_#define_32

#include<bits/stdc++.h>
#define cs const
using namespace std;
typedef long long ll;
ll read(){
ll cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
return cnt * f;
}
cs int N = 1e5 + 5;
int n, m; ll x, MAX;
ll t[N], b[N], sum[N]; int sz;
#define mid ((l+r)>>1)
int rt[N], ls[N * 25], rs[N * 25], vl[N * 25], node;
void ins(int &x, int las, int l, int r, int p){
x = ++node; ls[x] = ls[las]; rs[x] = rs[las]; vl[x] = vl[las] + 1;
if(l == r) return;
if(p <= mid) ins(ls[x], ls[las], l, mid, p);
else ins(rs[x], rs[las], mid+1, r, p);
}
int query(int x, int l, int r, int L, int R){
if(!x) return 0;
if(L<=l && r<=R) return vl[x]; int ans = 0;
if(L<=mid) ans += query(ls[x], l, mid, L, R);
if(R>mid) ans += query(rs[x], mid+1, r, L, R);
return ans;
}
#undef mid
bool ck(ll len, ll s){
int l = 1, r = n;
while(l < r){
int mid = (l+r) >> 1;
if(t[mid] > len) r = mid;
else l = mid + 1;
}
if(l == n && t[l] <= len) return true;
ll delta = len / x, ret = len % x;
int o = l;
ll ans = sum[o] - delta * (n - o + 1);
if(ans <= s) return true;
if(ret == 0) return false;
l = 0, r = sz;
while(l < r){
int mid = (l+r+1) >> 1;
if(ret >= b[mid]) l = mid;
else r = mid - 1;
} if(l) ans -= (ll)query(rt[o], 1, sz, 1, l);
return ans <= s;
}
int main(){
n = read(), m = read(), x = read();
for(int i = 1; i <= n; i++) t[i] = read(), MAX = max(MAX, t[i]);
sort(t + 1, t + n + 1);
for(int i = n; i >= 1; i--) sum[i] = sum[i + 1] + (t[i] - 1) / x + 1;
// 统计后缀和
for(int i = n; i >= 1; i--) b[++sz] = t[i] % x;
sort(b + 1, b + sz + 1); sz = unique(b + 1, b + sz + 1) - (b + 1);
for(int i = n; i >= 1; i--){
ll nx = t[i] % x;
rt[i] = rt[i + 1];
if(!nx) continue;
nx = lower_bound(b + 1, b + sz + 1, nx) - b;
ins(rt[i], rt[i], 1, sz, nx);
} // 主席树维护后缀模 x 为某一个值的个数
while(m--){
ll s = read();
ll l = 0, r = MAX;
while(l < r){
ll mid = (l+r) >> 1;
if(ck(mid + s, s)) r = mid;
else l = mid + 1;
} cout << l << '\n';
} return 0;
}

CSP-S 模拟 19/11/12_#define_33
钦定一个区间,考虑这个区间的贡献
就是强制填两个括号,然后两边随便填,方案数为 CSP-S 模拟 19/11/12_i++_34
发现之和 CSP-S 模拟 19/11/12_git_26 有关,对每一个 CSP-S 模拟 19/11/12_git_26 统计长度为 CSP-S 模拟 19/11/12_git_26 的数的和
考虑增量构造,长度为 1 的为 CSP-S 模拟 19/11/12_#define_38
长度为 2 的为 CSP-S 模拟 19/11/12_#define_39
长度为 3 的为 CSP-S 模拟 19/11/12_i++_40
就是上一次的减去最后一个乘 10 加上一个后缀和
在两个端点的区间分别考虑因为强制填的 CSP-S 模拟 19/11/12_i++_41 只有一个
复杂度 CSP-S 模拟 19/11/12_#define_42

#include<bits/stdc++.h>
#define cs const
using namespace std;
typedef long long ll;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
return cnt * f;
}
cs int N = 5e5 + 5;
cs int Mod = 998244353;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
int ksm(int a, int b){ int ans = 1; for(;b;b>>=1,a=mul(a,a)) if(b&1) ans = mul(ans, a); return ans; }
int n, k, sum[N]; char s[N];
int fac[N], ifac[N], pw[N];
int vl[N], f[N];
void prework(){
fac[0] = fac[1] = ifac[0] = ifac[1] = 1;
for(int i = 2; i <= n; i++) fac[i] = mul(fac[i - 1], i);
ifac[n] = ksm(fac[n], Mod - 2);
for(int i = n-1; i >= 2; i--) ifac[i] = mul(ifac[i + 1], i + 1);
pw[0] = 1;
for(int i = 1; i <= n; i++) pw[i] = mul(pw[i - 1], 10);
}
int calc(int l, int r){ return add(sum[r], Mod - mul(sum[l-1], pw[r - l + 1])); }
int C(int n, int m){
if(n < m || n < 0 || m < 0) return 0;
return mul(fac[n], mul(ifac[n-m], ifac[m]));
}
int main(){
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
n = read(), k = read(); scanf("%s", s + 1); prework();
for(int i = 1; i <= n; i++){
sum[i] = add(mul(sum[i-1], 10), s[i] - '0');
}
for(int i = n - 1; i >= 2; i--) vl[i] = add(vl[i + 1], s[i] - '0');
f[1] = vl[2];
for(int i = 2; i <= n - 2; i++){
f[i] = mul(10, add(f[i - 1], Mod - calc(n - i + 1, n - 1)));
f[i] = add(f[i], vl[i + 1]);
}
int ans = 0;
for(int i = 1; i <= n - 2; i++)
ans = add(ans, mul(f[i], C(n - i - 2, k - 2)));
for(int r = 1; r <= n; r++) ans = add(ans, mul(calc(1, r), C(n - r - 1, k - 1)));
for(int l = 2; l <= n; l++) ans = add(ans, mul(calc(l, n), C(l - 2, k - 1)));
cout << ans; return 0;
}