模拟赛7.13-7.18(week2)
7.13
100+20+0+0=120pts,rk31。
这辈子跟 31 过不去了哈。
打得简直就是一坨。
T1
求 \((a,b),a,b \leq n\) 的对数使得 \(a-b=\gcd(a,b)\)。
赛时 10min 写完。
正解
注意到 \(a-b=\gcd(a,b)=\gcd(b,a-b)\),令 \(a-b=t\),考虑枚举 \(t\),于是答案为:
直接整除分块,复杂度 \(O(\sqrt n)\)。
T2
原题 lg P8097
正解
赛时已经想到并查集,并且已经知道怎么合并了,但是忘了不用把答案赋值到每个点上,不然复杂度会爆。只需选择性地合并然后把答案赋值到连通块的祖先上(赛时想不到这个我是唐氏啊)。
考虑时光倒流,发现由于连边操作的点权值必须为 \(1\),所以反向操作无需删边,然后并查集维护一下即可。时间复杂度 \(O((n+q)\log n)\),没写按秩合并。
Code
#include<bits/stdc++.h>
#define int long long
#define gc getchar
#define pc putchar
#define rg register
#define LB lower_bound
#define UB upper_bound
#define PII pair<int, int>
#define PDI pair<double, int>
#define fi first
#define se second
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using db=double;using ll=long long;
using ull=unsigned long long;
using namespace std;
const ll INF=1e18;
const int inf=0x3f3f3f3f;
namespace IO{
inline int read(){
int x=0,f=1;
char ch=gc();
while(!isdigit(ch)){
if(ch=='-') f=-f;
ch=gc();
}
while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=gc();
return x*f;
}
inline void write(int x){
if(x<0) pc('-'),x=-x;
if(x>9) write(x/10);
pc(x%10+'0');
}
}
using namespace IO;
const int N=1e5+10;
int n,q,fa[N],ans[N],cnt,w[N];
inline void init(){for(rg int i=1;i<=n;i++) fa[i]=i,w[i]=1;}
inline int find(int x){return (x==fa[x])?fa[x]:fa[x]=find(fa[x]);}
struct edge{int u,v,del;}e[N<<1];
struct node{char op;int a,b;}qry[N<<1];
signed main(){
// freopen("114514.in","r",stdin);
// freopen("114514.out","w",stdout);
IOS
cin>>n>>q;init();
for(rg int i=1;i<=q;i++){
cin>>qry[i].op;
if(qry[i].op=='A'){
cin>>qry[i].a>>qry[i].b;
e[++cnt].u=qry[i].a,e[cnt].v=qry[i].b;
}else if(qry[i].op=='D'){
cin>>qry[i].a;
w[qry[i].a]=0;
}else if(qry[i].op=='R'){
cin>>qry[i].a;
e[qry[i].a].del=1;
}
}
for(rg int i=1;i<=cnt;i++){
if(!e[i].del){
int u=e[i].u,v=e[i].v;
int fu=find(u),fv=find(v);
if(fu==fv) continue;
if(w[fu]||w[fv]) w[fu]=w[fv]=1,ans[fu]=ans[fu]=q;
else fa[fu]=fv;
}
}
for(rg int i=1;i<=n;i++) if(w[i]) ans[find(i)]=q;
for(rg int i=q;i>=1;i--){
if(qry[i].op=='R'){
int u=e[qry[i].a].u,v=e[qry[i].a].v;
int fu=find(u),fv=find(v);
if(fu==fv) continue;
if(!w[fu]&&!w[fv]) fa[fu]=fv;
if(w[fu]&&!w[fv]) w[fv]=1,ans[fv]=i-1;
if(w[fv]&&!w[fu]) w[fu]=1,ans[fu]=i-1;
}else if(qry[i].op=='D'){
int u=find(qry[i].a);
if(!w[u]) w[u]=1,ans[u]=i-1;
}
}
for(rg int i=1;i<=n;i++) cout<<ans[find(i)]<<'\n';
return 0;
}
T3
原题 lg P7219。
赛时连部分分都不会。
Code
#include<bits/stdc++.h>
#define int long long
#define gc getchar
#define pc putchar
#define rg register
#define LB lower_bound
#define UB upper_bound
#define PII pair<int, int>
#define PDI pair<double, int>
#define fi first
#define se second
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using db=double;using ll=long long;
using ull=unsigned long long;
using namespace std;
const ll INF=1e18;
const int inf=0x3f3f3f3f;
namespace IO{
inline int read(){
int x=0,f=1;
char ch=gc();
while(!isdigit(ch)){
if(ch=='-') f=-f;
ch=gc();
}
while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=gc();
return x*f;
}
inline void write(int x){
if(x<0) pc('-'),x=-x;
if(x>9) write(x/10);
pc(x%10+'0');
}
}
using namespace IO;
const int N=2e5+10;
vector<int> f[N];
vector<PII> v[N];
int n,m,fal[N],far[N],tree[N];
inline int lbt(int x){return x&-x;}
inline void add(int i, int x){while(i<=n){tree[i]+=x;i+=lbt(i);}}
inline int query(int i){int ans=0; while(i>0){ans+=tree[i];i-=lbt(i);} return ans;}
inline int findl(int x){return (fal[x]==x)?fal[x]:fal[x]=findl(fal[x]);}
inline int findr(int x){return (far[x]==x)?far[x]:far[x]=findr(far[x]);}
signed main(){
// freopen("114514.in","r",stdin);
// freopen("114514.out","w",stdout);
n=read();
for(rg int i=1;i<=n;i++){
int x=read();
f[x].push_back(i);
}
for(rg int i=0;i<=n+1;i++) fal[i]=far[i]=i;
m=read();
for(rg int i=1;i<=m;i++){
int x=read(),y=read(),c=read();
v[y].push_back({x,c});
}
int ans=0;
for(rg int i=1;i<=n;i++){
for(auto j:v[i]){
int cost=query(j.fi);
if(j.se<=cost) ans+=j.se;
else ans+=cost,add(findl(j.fi)+1,j.se-cost),add(findr(j.fi),cost-j.se);
}
for(int j:f[i]) fal[findl(j)]=findl(j-1),far[findr(j)]=findr(j+1);
}
write(ans);
return 0;
}
T4
原题 CF2002H
神秘 dp 套 dp,很抽象,本人并不会。
7.14
100+10+10+0=120pts,rk19。
T1
给定一个序列,将其分成若干个区间,要求区间最小值在区间左端点,最大值在右端点,求最少能分成几段。
赛时 10min 想出做法,写了个分治发现是正确的但是会被极端数据卡,于是考虑 RMQ 结果调了1h 没调出来,浪费了很多时间。
正解
考虑贪心,设区间 min 的最左端出现位置为 \(l\),区间 max 最右端出现位置为 \(r\),如果 \(l<r\) 则取 \([l,r]\) 为一段更优,剩下两段继续分治;否则考虑分成三段分治。区间最值如果线性求,数据足够随机确实是 \(O(n \log n)\),但是存在单调递减的极端数据,所以可以考虑用 ST 表预处理,分治是 \(O(\log n)\) 到 \(O(n)\) 之间,预处理 \(O(n \log n)\)。
cmh 给的题解里有 \(O(n)\) 的 dp 做法,需要用到单调栈,此外还有许多大佬有不同的 \(O(n \log n)\) 做法,T1 直接过了一车。
Code
#include<bits/stdc++.h>
#define int long long
#define gc getchar
#define pc putchar
#define rg register
#define LB lower_bound
#define UB upper_bound
#define PII pair<int, int>
#define PDI pair<double, int>
#define fi first
#define se second
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using db=double;using ll=long long;
using ull=unsigned long long;
using namespace std;
const ll INF=1e18;
const int inf=0x3f3f3f3f;
namespace IO{
inline int read(){
int x=0,f=1;
char ch=gc();
while(!isdigit(ch)){
if(ch=='-') f=-f;
ch=gc();
}
while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=gc();
return x*f;
}
inline void write(int x){
if(x<0) pc('-'),x=-x;
if(x>9) write(x/10);
pc(x%10+'0');
}
}
using namespace IO;
const int N=3e5+10;
int n,b[N],lg[N];
PII a[N];
PII fmx[N][21],fmi[N][21];
//vector<int> p[N];
bool cmp(PII x, PII y){
if(x.fi!=y.fi) return x.fi<y.fi;
return x.se<y.se;
}
PII cmax(PII x, PII y){return (cmp(x,y)?y:x);}
PII cmin(PII x, PII y){return (cmp(x,y)?x:y);}
inline void init(){
lg[1]=0;
for(rg int i=2;i<N;i++) lg[i]=lg[i>>1]+1;
for(rg int i=1;i<=n;i++) fmx[i][0]=fmi[i][0]=a[i];
for(rg int j=1;j<=lg[n];j++){
for(rg int i=1;i+(1<<j)<=n+1;i++){
fmx[i][j]=cmax(fmx[i][j-1],fmx[i+(1<<(j-1))][j-1]);
fmi[i][j]=cmin(fmi[i][j-1],fmi[i+(1<<(j-1))][j-1]);
}
}
}
PII querymx(int l, int r){int k=lg[r-l+1];return cmax(fmx[l][k],fmx[r-(1<<k)+1][k]);}
PII querymi(int l, int r){int k=lg[r-l+1];return cmin(fmi[l][k],fmi[r-(1<<k)+1][k]);}
inline int solve(int l, int r){
if(r<l) return 0;
if(l==r) return 1;
PII p=querymx(l,r),q=querymi(l,r);
int mxpos=p.se,mipos=q.se;
// write(mxpos),pc(' '),write(mipos),puts("");
if(mipos<mxpos) return solve(l,mipos-1)+solve(mxpos+1,r)+1;
else return solve(l,mxpos)+solve(mxpos+1,mipos-1)+solve(mipos,r);
}
signed main(){
freopen("divide.in","r",stdin);
freopen("divide.out","w",stdout);
n=read();
for(rg int i=1;i<=n;i++) a[i].fi=read(),a[i].se=i;
init();
// write(querymx(1,n).fi);
write(solve(1,n));
return 0;
}
T2
给了你一个 \(n × m\) 的网格,网格的每个格子上写有一个字符,保证其为数字(\(1\) ∼ \(9\)),
加号(\(+\)),乘号(\(∗\))中的一个。
每次从左上角走到右下角,只能向右或向下,对于每条合法路径,它的权值为走过的表达式的值,求所有路径的权值和,结果模 \(998244353\)。
我甚至爆搜都写不来。
赛时写了个没有运算符的部分分。
正解
考虑 dp,具体地我们维护四个数组,分别为 \(cnt,x,y,z\),表示当前点路径数、上一个加号后到上一个乘号前的乘积,上一个加号后到当前点的总乘积,上一个加号前的和。
分别从 \((i-1,j),(i,j-1)\) 转移,若当前为 \(*\):
若当前为 \(+\):
若当前为数:
时间复杂度 \(O(nm)\)。
Code
#include<bits/stdc++.h>
#define int long long
#define gc getchar
#define pc putchar
#define rg register
#define LB lower_bound
#define UB upper_bound
#define PII pair<int, int>
#define PDI pair<double, int>
#define fi first
#define se second
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using db=double;using ll=long long;
using ull=unsigned long long;
using namespace std;
const ll INF=1e18;
const int inf=0x3f3f3f3f;
namespace IO{
inline int read(){
int x=0,f=1;
char ch=gc();
while(!isdigit(ch)){
if(ch=='-') f=-f;
ch=gc();
}
while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=gc();
return x*f;
}
inline void write(int x){
if(x<0) pc('-'),x=-x;
if(x>9) write(x/10);
pc(x%10+'0');
}
}
using namespace IO;
const int N=2e3+10,mod=998244353;
int n,m,cnt[N][N],x[N][N],y[N][N],z[N][N];
char ch[N][N];
inline void solve(int a, int b, int c, int d){
z[c][d]=(z[c][d]+z[a][b])%mod;
if(ch[c][d]=='+'){
x[c][d]=cnt[c][d]%mod;
y[c][d]=0;
z[c][d]=(z[c][d]+y[a][b])%mod;
}else if(ch[c][d]=='*'){
x[c][d]=(x[c][d]+y[a][b])%mod;
y[c][d]=0;
}else{
y[c][d]=(y[c][d]+10*y[a][b]%mod+(ch[c][d]-'0')*x[a][b]%mod)%mod;
x[c][d]=(x[c][d]+x[a][b])%mod;
}
}
signed main(){
freopen("gridwalk.in","r",stdin);
freopen("gridwalk.out","w",stdout);
IOS
cin>>n>>m;
for(rg int i=1;i<=n;i++) for(rg int j=1;j<=m;j++) cin>>ch[i][j];
x[1][1]=cnt[1][1]=1,y[1][1]=ch[1][1]-'0',z[1][1]=0;
for(rg int i=1;i<=n;i++){
for(rg int j=1;j<=m;j++){
if(i==1&&j==1) continue;
cnt[i][j]=(cnt[i-1][j]+cnt[i][j-1])%mod;
if(i==1) solve(i,j-1,i,j);
else if(j==1) solve(i-1,j,i,j);
else solve(i-1,j,i,j),solve(i,j-1,i,j);
}
}
cout<<(y[n][m]+z[n][m])%mod;
return 0;
}
T3
原题 ARC030D
赛时就写了个 10pts 的线段树。
正解是 FHQ 加可持久化等神秘操作,太难了本人并不会。
T4
平面上有 \(2n + 1\) 个点,两个点可以构成一组配对当且仅当它们的横坐标或纵坐标相等。
对于从 \(1\) 到 \(2n + 1\) 的每个 \(i\),询问在去掉第 \(i\) 个点后,剩下 \(2n\) 个点是否能配成 \(n\) 组配对,
满足每个点恰好出现在一组配对中。每次询问间互相独立。
本人并不会,但是拜谢 ljx 巨佬的神秘做法,简单易懂%%%。
7.15
100+0+0+0=100pts,鉴定为废物。
T1 10min 写完又他妈在死磕 T2,但是还是脑子不够,推不出答案,然后红温效应导致暴力也不想写了。
今天讲课是 TJM。
T1
原题 AT_tenka1_2012_final_a
贪心即可,过于简单。
T2
原题 lg P7322
想了很久,但并不知道如何求每个数的贡献。
正解
算 \([k,n]\) 每个数的贡献,\(i\) 为最大值的区间个数为个数为 \(A_{i-1}^{m-1}m(n-m+1)!\),但是有重复,考虑去重,重复数为 \(A_{i-1}^m(m-1)(n-m)!\)。
直接 \(O(n)\) 求和即可。
Code
#include<bits/stdc++.h>
#define int long long
#define gc getchar
#define pc putchar
#define rg register
#define LB lower_bound
#define UB upper_bound
#define PII pair<int, int>
#define PDI pair<double, int>
#define fi first
#define se second
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using db=double;using ll=long long;
using ull=unsigned long long;
using namespace std;
const ll INF=1e18;
const int inf=0x3f3f3f3f;
namespace IO{
inline int read(){
int x=0,f=1;
char ch=gc();
while(!isdigit(ch)){
if(ch=='-') f=-f;
ch=gc();
}
while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=gc();
return x*f;
}
inline void write(int x){
if(x<0) pc('-'),x=-x;
if(x>9) write(x/10);
pc(x%10+'0');
}
}
using namespace IO;
const int N=5e5+10;
const int mod=998244353;
int n,m,fac[N],inv[N];
inline int qpow(int x, int y){
int ans=1;
while(y>0){
if(y&1) ans=ans*x%mod;
x=x*x%mod,y>>=1;
}
return ans%mod;
}
inline void init(){
fac[0]=1;
for(rg int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;
inv[n]=qpow(fac[n],mod-2);
for(rg int i=n;i>=1;i--) inv[i-1]=inv[i]*i%mod;
}
signed main(){
// freopen("114514.in","r",stdin);
// freopen("114514.out","w",stdout);
n=read(),m=read();
init();
int ans1=0,ans2=0;
for(rg int i=m;i<=n;i++){
ans1=(ans1+fac[i-1]%mod*inv[i-m]%mod)%mod;
ans2=(ans2+fac[i-1]%mod*inv[i-m-1]%mod)%mod;
}
ans1=ans1*fac[n-m+1]%mod*m%mod;
ans2=ans2*fac[n-m]%mod*(m-1)%mod;
write((ans1-ans2+mod)%mod);
return 0;
}
T3
神秘数据结构优化 dp。
T4
原题 lg P10675。
tjm 出的。
本人并不会,机房有巨佬场切了%%%%%%。
7.16
100+100+0+0=200pts,rk7。
第一次上 200。
T1T2
过于简单。
T3
初始有 \(1\) 个金币,进行 \(n\) 次赌博,每次下注任意正整数个,一半的概率失去全部赌注,一半概率获得赌注的两倍,可以使用 \(m\) 次技能预测赌局结果并改变,求最优决策下期望获得的最多金币数。
样例都没看懂,我是飞舞。
70pts
拜谢巨佬 ycy(lg:I_LOVE_FG)。
设 \(f_{i,j}\) 为第 \(i\) 局用了 \(j\) 次技能获得期望最大值,考虑转移,有:
正是杨辉三角,于是 \(f_{i,j}=C_i^j\),答案即为:
时间复杂度 \(O(\sum m)\)
正解是莫队,参考 AT_tenka1_2014_final_d
T4
树上 dp,本人并不会。
7.18
80+10+0+0=90pts,rk114514。
ryh 怎么又 AK 了。
T1
给定非负整数 \(n,m\),你需要求出在平面直角坐标系上从 \((0,0)\) 出发,每步只能进行以下两种操作中的一种:
- 使 \(x\) 坐标增加 \(1\)。
- 使 \(y\) 坐标增加 \(1\)。
你需要求出在不跨过直线 \(x=y\) 的情况下到达 \((n,m)\) 的方案数,对 \(998244353\) 取模。
正解
考虑反射容斥,钦定 \(n>m\),答案为 \(C_{n+m}^n-C_{n+m}^{m-1}\)。
注意 \(n=m\) 时要乘个二,都为零时答案为 \(1\)。
赛时这两个没特判挂了 20pts,警钟撅烂。
T2
称一个长度为 \(n\) 的序列 \(a_1,\dots,a_n\) 合法当且仅当对于任意 \(i(2\le i\le n-1)\) 都满足以下两个条件中的至少一个:
- \(\forall 1\le j\le i-1,a_j\le a_i\)。
- \(\forall i+1\le j\le n,a_j\le a_i\)。
现在给你一个长度为 \(n\) 的序列 \(a_1,\dots,a_n\),你需要求出至少执行多少次以下操作才能使序列 \(a_1,\dots,a_n\) 合法:
- 选定 \(i(1\le i\le n-1)\),交换 \(a_i,a_{i+1}\)。
赛时想了 3h30min 的逆序对,发现是假的。原因是枚举最大值位置时,存在最大值两边互换更优的情况。一车人错的一样。
正解
考虑最终序列一定是一个单峰序列,考虑对每个数算贡献,其实是 \([1,i]\) 大于 \(a_i\) 的数个数与 \([i+1,n]\) 取 min,直接离散化加权值树状数组维护。
Code
#include<bits/stdc++.h>
#define int long long
#define gc getchar
#define pc putchar
#define rg register
#define LB lower_bound
#define UB upper_bound
#define PII pair<int, int>
#define PDI pair<double, int>
#define fi first
#define se second
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using db=double;using ll=long long;
using ull=unsigned long long;
using namespace std;
const ll INF=1e18;
const int inf=0x3f3f3f3f;
namespace IO{
inline int read(){
int x=0,f=1;
char ch=gc();
while(!isdigit(ch)){
if(ch=='-') f=-f;
ch=gc();
}
while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=gc();
return x*f;
}
inline void write(int x){
if(x<0) pc('-'),x=-x;
if(x>9) write(x/10);
pc(x%10+'0');
}
}
using namespace IO;
const int N=3e5+10;
inline int lbt(int x){return x&-x;}
int n,a[N],b[N],p[N],q[N];
struct BIT{
int tree[N];
inline void clear(){memset(tree,0,sizeof tree);}
inline void add(int x, int d){while(x<=n){tree[x]+=d,x+=lbt(x);}}
inline int query(int x){int ans=0;while(x>0){ans+=tree[x],x-=lbt(x);}return ans;}
}T;
inline void solve(){
for(rg int i=1;i<=n;i++) p[i]=T.query(n)-T.query(a[i]),T.add(a[i],1);
T.clear();
for(rg int i=n;i>=1;i--) q[i]=T.query(n)-T.query(a[i]),T.add(a[i],1);
}
signed main(){
freopen("seq.in","r",stdin);
freopen("seq.out","w",stdout);
n=read();
for(rg int i=1;i<=n;i++) a[i]=read(),b[i]=a[i];
sort(b+1,b+1+n);
int tot=unique(b+1,b+1+n)-b-1;
for(rg int i=1;i<=n;i++) a[i]=LB(b+1,b+1+tot,a[i])-b;
solve();
int ans=0;
for(rg int i=1;i<=n;i++) ans+=min(p[i],q[i]);
write(ans);
return 0;
}
/*
7
2 8 4 8 5 3 6
*/
T3
给定一张 \(n\) 个点 \(n\) 条边的有向图,第 \(i(1\le i\le n)\) 条边为 \(i\rightarrow p_i\)。
你可以进行如下操作:
- 选择 \(i(1\le i\le n)\),将 \(p_i\) 修改为 \(\{1,2,\dots,n\}\) 中的任意一个数,代价为 \(c_i\)。
你需要进行一系列操作使得最后得到的 \(\forall 1\le i\le n,i\rightarrow p_i\) 的图强连通,并最小化代价之和。
我不会,膜拜 tyh 爆切本题。
T4
原题 lg P12485。
TJM 出的,本人太菜并不会。
7.18
有史以来打的最差的一次,小基班 rk-1,不愧是我,纯废物。
T1
lg P8106
过于简单。
凭啥评绿。
T2

赛时想了个唐人做法,以为是对的,结果未知原因写炸了。
正解
按照奇偶性做,是一个类似括号匹配的东,用栈维护并统计最值。
std
#include<bits/stdc++.h>
#define fir first
#define sec second
#define all(x) begin(x),end(x)
using namespace std;
typedef long long ll;
typedef unsigned uint;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<int,int> pii;
template<typename type>
inline void chmin(type &x,const type &y)
{
if(y<x)
x=y;
}
template<typename type>
inline void chmax(type &x,const type &y)
{
if(x<y)
x=y;
}
constexpr int Max=1e6+10;
int n,a[Max],s[Max],o=1,ans[Max];
signed main()
{
freopen("domino.in","r",stdin),freopen("domino.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
auto solve=[&]()->void
{
cin>>n;
int top=0;
for(int i=1;i<=n;++i)
{
cin>>a[i];
if(top&&(a[i]&1)==(s[top]&1))
{
chmax(s[top-1],max(a[i],s[top])+1);
--top;
}
else
s[++top]=a[i];
if(top>1)
ans[i]=-1;
else
if(top==1)
ans[i]=max(s[0]-((s[0]^s[1])&1),s[1]);
else
ans[i]=s[0]-1;
}
if(o==1)
cout<<ans[n]<<"\n";
else
for(int i=1;i<=n;++i)
cout<<ans[i]<<" \n"[i==n];
fill(s,s+n+1,0);
};
int t;
cin>>t>>o;
while(t--)
solve();
return 0;
}
T3
给定非负整数 \(k\),求出长度为 \(n\) 的逆序对数恰好为 \(k\) 的排列的个数。
有个 70pts 的 \(O(nk)\) dp,我直接没写,这是怎么回事呢?
#include<bits/stdc++.h>
using namespace std;
const int mod=1000000007;
int f[5010][5010];
int n,k;
int main(){
scanf("%d%d",&n,&k);
f[1][0]=1;
for(int i=2;i<=n;i++){
for(int j=1;j<=k;j++) f[i-1][j]=(f[i-1][j]+f[i-1][j-1])%mod;
for(int j=0;j<i;j++) f[i][j]=f[i-1][j];
for(int j=i;j<=k;j++) f[i][j]=(f[i-1][j]-f[i-1][j-i]+mod)%mod;
}
printf("%d\n",f[n][k]);
return 0;
}
T4
神秘淀粉质。

浙公网安备 33010602011771号