- 直接
,
,前缀和优化,只有
个有用位置
#include<bits/stdc++.h>
#define cs const
using namespace std;
cs int Mod = 1e9 + 7;
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 dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int ksm(int a, int b){ int as=1; for(;b;b>>=1,a=mul(a,a)) if(b&1) as=mul(as,a); return as; }
void Add(int &a, int b){ a = add(a, b); }
void Mul(int &a, int b){ a = mul(a, b); }
cs int N = 1e5 + 50;
int n, m, S, sum[N];
int ps1[N], ps2[N], nd, vl[N];
int idx(int x){ if(x <= S) return ps1[x]; return ps2[m/x]; }
int main(){
freopen("noname.in","r",stdin);
freopen("noname.out","w",stdout);
cin >> n >> m; S = sqrt(m); int c = 0;
for(int l = 1, r; l <= m; l = r+1) r = m / (m / l), ++c;
nd = c;
for(int l = 1, r; l <= m; l = r+1){
int v = m / l; r = m / v;
(v <= S) ? ps1[v] = c-- : ps2[m/v] = c--;
sum[c+1] = vl[c+1] = v;
}
for(int t = 1; t < n; t++){
static int nxt[N];
for(int i = 1; i <= nd; i++){
nxt[i] = add(nxt[i-1], mul(vl[i]-vl[i-1], sum[idx(m/vl[i])]));
} memcpy(sum, nxt, sizeof(int)*(nd+1));
} cout << sum[nd]; return 0;
}
- 思路挺巧妙的,我开始想的是考虑一个数插头插尾的贡献用个线段树之类的维护(放后面是区间加,放前面是查询最大值),应该也可以
正解比较妙,考虑将序列反过来赋值一遍拼在前面,那么就是前面选一个子序列后面选一个子序列子序列不相交,最大化,发现严格递增的
一定不会相交,所以对新序列求一个
就可以了
#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 = 1e5 + 50;
int n, A[N]; set<int> S;
typedef set<int>::iterator It;
int main(){
freopen("dequexlis.in","r",stdin);
freopen("dequexlis.out","w",stdout);
n = read();
for(int i = 1; i <= n; i++) A[i] = read();
for(int i = n; i >= 1; i--){
It it = S.lower_bound(A[i]);
if(it == S.end()) S.insert(A[i]);
else S.erase(it), S.insert(A[i]);
}
for(int i = 1; i <= n; i++){
It it = S.lower_bound(A[i]);
if(it == S.end()) S.insert(A[i]);
else S.erase(it), S.insert(A[i]);
} cout << S.size(); return 0;
}
- 不是很难,但蛮有趣的,考虑 1 为向上走,-1 为向右走,那么贡献就是与
相交的
的最大值,考虑统计每一个
有多少个,容斥一下求
的那么方案数就是
,跟卡特兰数差不多
#include<bits/stdc++.h>
#define cs const
using namespace std;
cs int N = 2e6 + 50;
cs int Mod = 998244853;
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 dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int ksm(int a, int b){ int as=1; for(;b;b>>=1,a=mul(a,a)) if(b&1) as=mul(as,a); return as; }
void Add(int &a, int b){ a = add(a, b); }
void Mul(int &a, int b){ a = mul(a, b); }
int fix(int a){ return a < 0 ? -a : a; }
int n, m, fac[N], ifac[N];
int C(int n, int m){ if(n<0||m<0||n<m) return 0; return mul(fac[n],mul(ifac[n-m],ifac[m])); }
void prework(int n){
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);
}
int main(){
freopen("maxpsum.in","r",stdin);
freopen("maxpsum.out","w",stdout)
cin >> n >> m; prework(n+m); int as = 0;
for(int i = max(1,n-m); i <= n; i++)
Add(as, mul(i,dec(C(n+m, m+i),C(n+m, m+i+1))));
cout << as; return 0;
}