因为感觉题解写不了多少,,,就懒得一道道题目慢慢写了,汇总了算了$QAQ$

昂然后因为我估计以后还会有些什么$dp$专题啊$balabala$的,,,然后谢总肯定又会建一堆小组啥的,,,所以还是放个链接防止自己忘了题目都是啥$QAQ$

1:

$A$

先放下题目大意昂$QwQ$,就说给定$N$个人,$K$排,以及每排的人数$a_{1},...,a_{K}$,现要求每排人数递减,然后每列人数也递减,求排列方案数

显然考虑从矮到高考虑,就有一定要是满足轮廓是个凸的,就长得有点儿像之前寒假考试的搜索专题$D2\ T5$

这题就差不多套路,考虑五维$dp$:设$f_{d_1,d_2,d_3,d_4,d_5}$,然后判断$d_1\leqslant d_2$这种之类乱七八糟的条件,然后瞎转移一下,就欧克了

嗷对辣,就是,因为如果直接开$f_{30,30,30,30,30}$会炸空间,,,所以这里要对着读入开,,,啊呀说不清楚还是看$code$趴$QwQ$(,,,后来发现是我呆了,更优秀的开空间方式可以看神仙hl的博客$QwQ$

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<map>
using namespace std;
#define il inline
#define gc getchar()
#define int long long
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i) const int M=+,N=1e7;
int n,as,a[M];
bool gdgs=; il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:x;
} signed main()
{
while(gdgs)
{
ri n=read();if(!n)return ;rp(i,,n)a[i]=read();rp(i,n+,)a[i]=;
int f[a[]+][a[]+][a[]+][a[]+][a[]+];memset(f,,sizeof(f));f[][][][][]=;
rp(i,,a[])
{
rp(j,,min(a[],i))
{
rp(k,,min(a[],j))
{
rp(p,,min(a[],k))
{
rp(q,,min(a[],p))
{
if(q)f[i][j][k][p][q]+=f[i][j][k][p][q-];
if(p->=q)f[i][j][k][p][q]+=f[i][j][k][p-][q];
if(k->=p)f[i][j][k][p][q]+=f[i][j][k-][p][q];
if(j->=k)f[i][j][k][p][q]+=f[i][j-][k][p][q];
if(i->=j)f[i][j][k][p][q]+=f[i-][j][k][p][q];
}
}
}
}
}
printf("%lld\n",f[a[]][a[]][a[]][a[]][a[]]);
}
return ;
}

$B$

先翻译下$QAQ$?大概就是说有两个序列,然后求最长公共上升子序列

显然考虑$dp$呗,就设$f_{i,j}$:$a_{i}$和$b_{j}$配对的最长方案数

然后直接$O(T\cdot n^{2})$地做就好了鸭,具体来说就,把$a$作外层,$O(n^{2})$地扫,碰到两个情况要记录,第一个是$a_{i}=b_{j}$,显然考虑转移,问题就在于要找到在$j$之前的满足$b_{k}<a_{i}$的$f_{max}$.所以在碰到$a_{i}>b_{j}$的情况的时候就顺便记录下所有满足的$f_{max}$即可

至于输出方案就另开一个数组记录就好,,,挺水的懒得说了_(:з」∠)_

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
#define il inline
#define gc getchar()
#define int long long
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i) const int M=+;
int n,a[M],f[M][M],b[M],pre[M][M]; il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
} signed main()
{
// freopen("qwq.in","r",stdin);freopen("b.out","w",stdout);
ri T=read();
while(T--)
{
ri n=read();rp(i,,n)a[i]=read();ri m=read();rp(i,,m)b[i]=read();
memset(f,,sizeof(f));memset(pre,-,sizeof(pre));
rp(i,,n)
{
ri tmp_f=,tmp_j=;
rp(j,,m)
{
f[i][j]=f[i-][j];
if(a[i]>b[j] && tmp_f<f[i-][j])tmp_f=f[i-][j],tmp_j=j;
if(a[i]==b[j] && tmp_f+>f[i][j])f[i][j]=tmp_f+,pre[i][j]=tmp_j;
}
}
ri tmp_i=;rp(i,,m)if(f[n][i]>f[n][tmp_i])tmp_i=i;printf("%lld\n",f[n][tmp_i]);
if(!f[n][tmp_i])continue;
vector<int>as;my(i,n,)if(pre[i][tmp_i]!=-)as.push_back(a[i]),tmp_i=pre[i][tmp_i];printf("%lld",as[as.size()-]);
my(i,as.size()-,)printf(" %lld",as[i]);printf("\n");
}
return ;
}

$C$

这题长得有点儿像$HNOI2019\ D2T3$的10$pts$部分分那个,,,?

不过那题的数据范围是$1e3$,这题是$1e9$鸭$QAQ$

所以显然直接$dp$是不可取的,这里需要大胆猜结论发现,新的数列$b$一定都是原来的数列$a$中的数

瞎证下趴,,,$QAQ$

下面只尝试着证下在单调增的序列中,单调减同理即可$QwQ$

首先显然的是新的数列$b$中的每个数都一定在$[min_{a},max_{a}]$的范围内?

若最优解中$b_{i}$不在$a$中且属于$[a_{j},a_{j+1}]$,那它的下一个数的取值范围就在$[b_{i},+\infty]$

首先,如果$abs(a_{j}-a_{i})\leqslant abs(b_{i}-a_{i})$,显然选$a_{j}$更好,数据范围更大而且答案又更小

那如果是$|a_{j+1}-a_{i}|\leqslant |b_{i}-a_{i}|$(显然一定有一遍是满足小于等于的,,,这个太显然了趴$QwQ$),那如果取$a_{i}$,就相当于是范围变小了,但是值也变小了.考虑如果取的是$a_{j+1}$,对于下一个数,如果第$i+1$位的最优解大于等于$a_{j+1}$,那范围根本就不重要,显然$a_{j+1}$就是第$i$位的最优解,然后如果最优解小于$a_{j+1}$,显然的是这个亏了的部分能在$|b_{i}-a_{i}|-|a_{j+1}-a_{i}|$中找补回来,也就是说把$a_{j+1}$当最优解是不亏的

综上,可以证明,新的数列$b$一定都是原数列$a$中的数,$over$

以上证得非常扯淡,,,还是放下$TT$小朋友滴题解,,,里面有证明,,,挺详细的来着$QwQ$

总之呢,既然知道了这个结论,就能直接设$f_{i,j}$:$b_{i}$取$a_{j}$的最小代价,然后正着反着分别做一遍就好$QwQ$

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
using namespace std;
#define il inline
#define gc getchar()
#define int long long
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i) const int M=+;
int n,as,a[M],b[M],f[M][M],tmp; il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:x;
}
il int abss(ri x){return x>?x:-x;}
il int work1()
{
memset(f,,sizeof(f));rp(i,,n)f[][i]=;
rp(i,,n)rp(j,,n){f[i][j]=f[i][j-];f[i][j]=min(f[i][j],f[i-][j]+abss(b[i]-a[j]));}
tmp=f[n][];rp(i,,n)tmp=min(tmp,f[n][i]);
return tmp;
}
il int work2()
{
memset(f,,sizeof(f));rp(i,,n)f[][i]=;
rp(i,,n)my(j,n,){f[i][j]=f[i][j+];f[i][j]=min(f[i][j],f[i-][j]+abss(a[j]-b[i]));}
tmp=f[n][];rp(i,,n)tmp=min(tmp,f[n][i]);
return tmp;
} main()
{
n=read();rp(i,,n)a[i]=b[i]=read();sort(a+,a++n);
as=work1();as=min(as,work2());
printf("%lld\n",as);
return ;
}

$D$

大致题意是,有$n$个人,每个人有2个属性$d_{i}$和$p_{i}$,然后要求从中选出$m$个数,最小化$\left | \sum d-\sum p \right |$,然后如果有多个相等的$ \left | \sum d - \sum p \right | $,就输出$\sum d + \sum p$最大的

显然考虑$dp$鸭,考虑设$f_{i,j}$表示选了$i$个人,$d-p=j$的$( \sum d + \sum p)_{max}$

大力转移就好?记录路径什么的懒得写辣自己瞎搞一通就好昂_(:з」∠)_

然后就做完辣?

$over?$

然后很迷的是我用$spj$拍了下,拍了几千组都对的,感$jio$稳得布星就交了,交了之后发现$WA$了,,,?我说不出来我想不明白$TT$

不管了我先放下我$code$,,,对了这题神仙$hl$写了$spj$如果卡在这题的可以向他要$spj$鸭$QwQ$

$upd:$我放弃辽$QAQ$,,,,我最后拿的神仙$hl$的$code$过了$QAQ$

    所以就不放标程了,,,因为我也麻油打出来标程昂嘤嘤嘤

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
#define il inline
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i) const int N=+,M=+;
int n,m,cas,as_p,as_d,as[M],f[M][N];
bool gdgs=;
struct node{int d,p,dat,sum;}nod[M]; il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
}
il void solve()
{
vector<int>pth[M][N];
rp(i,,n){ri x=read(),y=read();nod[i]=(node){x,y,x-y,x+y};}
memset(f,-,sizeof(f));f[][]=;
rp(i,,n)
{
my(j,m,)
{
rp(k,nod[i].dat,)
{
if(f[j][k]<f[j-][k-nod[i].dat]+nod[i].sum && f[j-][k-nod[i].dat]!=-)
{f[j][k]=f[j-][k-nod[i].dat]+nod[i].sum;pth[j][k]=pth[j-][k-nod[i].dat];pth[j][k].push_back(i);}
}
}
}
rp(i,,)
{
if(f[m][+i]!=-)
{
if(f[m][+i]>f[m][-i]){ri tmp=,sz=pth[m][+i].size();rp(j,,sz-)as[++tmp]=pth[m][+i][j];break;}
else{ri tmp=,sz=pth[m][-i].size();rp(j,,sz-)as[++tmp]=pth[m][-i][j];break;}
}
if(f[m][-i]!=-){ri tmp=,sz=pth[m][-i].size();rp(j,,sz-)as[++tmp]=pth[m][-i][j];break;}
}
rp(i,,m)as_d+=nod[as[i]].d,as_p+=nod[as[i]].p;
} int main()
{
// freopen("in.in","r",stdin);freopen("out.out","w",stdout);
while(gdgs)
{
n=read();m=read();if(!n && !m)return ;printf("Jury #%d\n",++cas);
solve();
printf("Best jury has value %d for prosecution and value %d for defence:\n",as_d,as_p);rp(i,,m)printf(" %d",as[i]);printf("\n\n");
}
return ;
}

$E$

多重背包板子鸭,,,?

既然复习了多重背包就$cue$下多重背包俩优化趴(虽然并不知道这题要不要$QwQ$?

一个是二进制分解;还一个是单调队列优化

都麻油太难不想写了,,,而且我应该之前写过来着$QwQ$?

昂然后这题,,,$gql$又呆了,,,越来越菜了$szd$,,,$QAQ$

先放下$gql$超呆的代码,,,打完就发现复杂度假得一批,,,显然过不去$QAQ$

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
#define il inline
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i) const int N=+,M=+;
int n,m,c[N],a[N],as;
bool gdgs=,f[M]; il bool cmp(node x,node y){return x.st<y.st;}
il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
} int main()
{
while(gdgs)
{
memset(f,,sizeof(f));f[]=;as=;
n=read();m=read();if(!n && !m)return ;
rp(i,,n)a[i]=read();rp(i,,n)c[i]=read();
rp(i,,n)rp(j,,c[i])rp(k,,m-a[i])vis[k+a[i]]|=f[k];
rp(i,,m)if(f[i])++as;printf("%d\m",as);
}
return ;
}

放下傻逼代码,,,呆死了$QAQ$

啊当然二进制分解优化下应该还是过得去,主要这个方法太呆了,,,所以不想说,还是说个正常点儿的想法$QAQ$

显然要考虑转化一下,,,比如$O(m\cdot n)$就还是能接受的,所以考虑怎么消除掉这个$c_{i}$

于是考虑加入一个数组$cd_{i,j}$表示要凑出数值$i$至少需要$j$种的数量,因为是一种种分开考虑的,所以显然可以降一维,直接$cd_{i,j}$就好,然后就转移的时候判一下需要的数量不超过$c_{j}$就好

然后就做完辣,,,?

真·$over$

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
#define il inline
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i) const int N=+,M=+;
int n,m,c[N],a[N],as,cd[M];
bool gdgs=,f[M]; il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
} int main()
{
while(gdgs)
{
memset(f,,sizeof(f));f[]=;as=;
n=read();m=read();if(!n && !m)return ;
rp(i,,n)a[i]=read();rp(i,,n)c[i]=read();
rp(i,,n){memset(cd,,sizeof(cd));rp(j,a[i],m)if(!f[j] && f[j-a[i]] && cd[j-a[i]]<c[i])f[j]=,cd[j]=cd[j-a[i]]+;}
rp(i,,m)if(f[i])++as;printf("%d\n",as);
}
return ;
}

$F$

中文可以看$luogu$上的$QwQ$

说个题外话.这题我印象中是个$dp$入门题昂,,,去年暑假谢总就讲过了的,,,?为什么在洛谷上有紫,,,?

瞎写下做法趴,显然考虑$f_{i,j}$,即$[i,j]$区间最大值,这时候发现有负负得正这种东西,于是考虑再存个$g$表示$min$嘛,然后就做完了,,,?

无脑转移就好$QwQ$?就$f_{i,j}=f_{i,k}\ operator_{k}\ f_{k+1,j}$,大概长这样儿,$g$什么的自己意会下就好,,,

然后环这个东西的处理,我开始很呆地想着枚举断哪条链然后$O(n^{4})$做,,,仔细思考下之后发现是我呆了$QAQ$直接倍长然后做就好$QAQ$

$over$

//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstdio>
using namespace std;
#define il inline
#define int long long
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i) const int N=+,inf=1e9;
int n,f[N][N],g[N][N],as;
bool vis[N][N];
struct node{char op;int x;}nod[N<<]; il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
}
il char rdch(){rc ch=gc;while(ch!='t' && ch!='x')ch=gc;return ch;}
il int cal(ri x,ri y,char op){if(op=='t')return x+y;return x*y;}
il int maxx(ri x,ri y,ri p,ri q){return max(max(x,y),max(p,q));}
il int minn(ri x,ri y,ri p,ri q){return min(min(x,y),min(p,q));}
il void solve(ri l,ri r)
{
if(vis[l][r])return;
vis[l][r]=;f[l][r]=-inf;g[l][r]=inf;
ri tmp_f,tmp_g;
rp(i,l,r-)
{
solve(l,i);solve(i+,r);ri mx,mn;
mx=maxx(cal(f[l][i],f[i+][r],nod[i+].op),cal(f[l][i],g[i+][r],nod[i+].op),cal(g[l][i],f[i+][r],nod[i+].op),cal(g[l][i],g[i+][r],nod[i+].op));
mn=minn(cal(f[l][i],f[i+][r],nod[i+].op),cal(f[l][i],g[i+][r],nod[i+].op),cal(g[l][i],f[i+][r],nod[i+].op),cal(g[l][i],g[i+][r],nod[i+].op));
if(mx>f[l][r])tmp_f=i;if(mn<g[l][r])tmp_g=i;
f[l][r]=max(f[l][r],mx);g[l][r]=min(g[l][r],mn);
}
} main()
{
freopen("4342.in","r",stdin);freopen("4342.out","w",stdout);
n=read();rp(i,,n)nod[i]=nod[i+n]=(node){rdch(),f[i][i]=g[i][i]=f[i+n][i+n]=g[i+n][i+n]=read()},vis[i][i]=vis[i+n][i+n]=;
solve(,n<<);
as=-inf;rp(i,,n)as=max(as,f[i][i+n-]);printf("%lld\n",as);rp(i,,n)if(as==f[i][i+n-])printf("%lld ",i);
return ;
}

$G$

占坑,晚上写$QwQ$

$H$

感$jio\ H$题好像比较水的样子$(bushi$,所以先来搞下$H$题嘻嘻

题意懒得放了,这种题目,显然看到就应该想到设$f_{i,j,0/1}$?就前$i$段时间休息了$j$段时间,然后第$i$段的状态是不是在睡觉.瞎转移一通就好,,,?

$over$

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
#define il inline
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i) const int N=4e3+;
int n,b,f[N][],u[N],as; il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
}
il void solve(){rp(i,,n)my(j,b,)f[j][]=max(f[j][],f[j][]),f[j][]=max(f[j-][],f[j-][]+u[i]);}
int main()
{
n=read();b=read();rp(i,,n)u[i]=read();
memset(f,,sizeof(f));f[][]=f[][]=;solve();as=max(f[b][],f[b][]);
memset(f,,sizeof(f));f[][]=u[];solve();as=max(as,f[b][]);
printf("%d\n",as);
return ;
}

$I$

题目大意就,有个机器人位于$(x,y)$,然后有四种操作,留在原地/向左/向右/向下,然后如果到了边界就不能再往边界上走了(即第一列不能往左走第$m$列不能往右走嘛$QwQ$),问到达最后一行的期望操作数是多少$QwQ$

不难列出转移式,就$f_{i,j}=\frac{f_{i,j}+f_{i,j+1}+f_{i,j-1}+f_{i+1,j}}{4}+1$(边界有点儿不一样,,,差不多就懒得另外写个了,,,推出来还是很$easy$的来着$QAQ$

然后这时候发现,就不管是按哪个顺序,$f_{i,j+1}$和$f_{i+1,j}$是一定有一个还麻油推出来的,,,$QAQ$

然后理论上是有两种处理方式的?

一个可以用高斯消元搞掉,一个比较基本的套路来着$QwQ$?

但还是大概港下好辣_(:з」∠)_

不难发现,每一行之间是无后效性的,相互影响的只有同一行的,也就是说当求$f_{i}$的时候$f_{i+1}$其实是已知的

于是考虑把$f_{i}$的式子都列出来,不难发现就变成了一个$m$元一次方程组,然后还刚好给了$m$个式子,那显然就可以解出来了昂$QwQ$

然后因为显然每个高斯消元系数矩阵每行都只会有2/3个地方有数,,,所以在$O(M)$的时间内就能解出来,,,所以复杂度是$O(MN)$的,还是挺稳的来着$QwQ$

另一个可以观察下这个式子,,,不难发现其实是有点儿规律的,,,所以找下规律($bushi$可以发现一个三角形式这种,然后就能线性算辣$QwQ$,,,

懒得详细写了,,,就只瞎写点儿东西,,,就很显然能发现答案一定是对称分布的,所以瞎推下就搞完辣,,,瞎扯的,瞎$get$下就好$QAQ$

$upd:$

做完辣!来记录几个坑$QAQ$

第一个是要防止控制数据范围防止爆炸,,,

主要可能是因为我不记得高斯消元板子辽,就手推了下,直接打了上去.

然后放这题,因为和普通的高斯消元实际上还是有点儿区别(否则复杂度会爆炸,,,$QAQ$

所以我的方法是,正着做一遍,就每行只会有1/2个地方有数了,再倒着做一遍,就每行只会有一个地方有系数了,就做完了

但是这儿要$attention$的是,如果直接做,比如我开始是这么打的(这是正着做一遍的$code$):

$g[i+1][m+1]=-(lf)g[i][i]/g[i+1][i]*g[i+1][m+1]+g[i][m+1];$

$g[i+1][i+1]=-(lf)g[i][i]/g[i+1][i]*g[i+1][i+1]+g[i][i+1];$

这么做的直接后果就是系数增长飞快,,,瞬间爆炸$QAQ$

所以在过程中一定要控制$g_{i,i}$那一位=1!就没事儿除下就好!

(反着做的时候一样儿,,,懒得写辣$QAQ$

第二个是要注意下$m=1$的情况

这个时候的式子是:$f_{i,1}=f_{i+1,1}+2$(懒得写过程了直接放变形之后的结果_(:з」∠)_

然后直接就可以得到$as=2\cdot (n-x)$,直接输出就好

$over$

然后就放下代码,,,因为我高斯消元掌握得不怎么好,所以给自己补了个注释,防止以后重看看不懂了$QAQ$

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
#define il inline
#define lf double
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i) const int N=+;
int n,m,x,y;
lf f[N][N];
/*高斯消元!*/
struct gdgs
{
lf g[N][N];
il void clr(){memset(g,,sizeof(g));}
il void solve()
{
/*这就正着做一遍嘛QwQ*/
rp(i,,m-)
{
/*这个就坑点里港的那个,防爆炸的code*/
g[i][m+]=(lf)g[i][m+]/g[i][i];g[i][i+]=(lf)g[i][i+]/g[i][i];g[i][i]=;
/*这个就坑点里港的那个,防爆炸的code*/
g[i+][m+]=-(lf)g[i][i]/g[i+][i]*g[i+][m+]+g[i][m+],g[i+][i+]=-(lf)g[i][i]/g[i+][i]*g[i+][i+]+g[i][i+];
if(i!=m-)g[i+][i+]=-(lf)g[i][i]/g[i+][i]*g[i+][i+];
g[i+][i]=;
}
/*这就正着做一遍嘛QwQ*/ /*这就反着做一遍嘛QwQ*/
my(i,m,)
{
/*这个就坑点里港的那个,防爆炸的code*/
g[i][m+]=(lf)g[i][m+]/g[i][i];g[i][i-]=(lf)g[i][i-]/g[i][i];g[i][i]=;
/*这个就坑点里港的那个,防爆炸的code*/
g[i-][m+]=-(lf)g[i][i]/g[i-][i]*g[i-][m+]+g[i][m+];g[i-][i-]=-(lf)g[i][i]/g[i-][i]*g[i-][i-];g[i-][i]=;
}
/*这就反着做一遍嘛QwQ*/
}
}lq;
/*高斯消元!*/ il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
}
il void dp(ri x)
{
/*瞎赋下系数嘛,懒得详细写了自己手推下就出来了,,,*/
lq.clr();lq.g[][]=;lq.g[][]=-;lq.g[m][m-]=-;lq.g[m][m]=;lq.g[][m+]=f[x+][]+;lq.g[m][m+]=f[x+][m]+;
rp(i,,m-)lq.g[i][i-]=lq.g[i][i+]=-,lq.g[i][i]=,lq.g[i][m+]=+f[x+][i];
/*瞎赋下系数嘛,懒得详细写了自己手推下就出来了,,,*/
lq.solve();
rp(i,,m)f[x][i]=(lf)lq.g[i][m+]/lq.g[i][i];
} int main()
{
// freopen("i.in","r",stdin);freopen("i.out","w",stdout);
n=read();m=read();x=read();y=read();
if(m==)return printf("%.6lf\n",(lf)*(n-x)),;
my(i,n-,x)dp(i);
printf("%.6lf\n",f[x][y]);
return ;
}
/*最后还要注意一个,,,就不要开long double昂,,,会T的QAQ */

$J$

首先考虑先判掉为0的$as$?不难想到除了面积为奇数以外不可能存在$as$的0的了,就可以先特判掉$QwQ$

考虑当第$i$行已经被填补满了的时候,因为有可能有的格子是竖着放的,就导致第$i+1$行实际上是千疮百孔的,$so$如果常规地设个$f_{i,j}$表示填到第$i$行第$j$个格子这样显然是不可取的$QAQ$,显然考虑状压下,设$f_{i,S}$表示前$i-1$行都已经填完了,然后第$i$行的状态是$S$时候的方案数

那转移就相当好想了?枚下这一行状态再枚这一行,然后判下是否合法转移下就做完辽$QwQ$

$upd:$还有个神仙方法,,,可以用轮廓线$dp$,,,然而太神仙了,,,菜鸡$gql$学不会$QAQ$

    神仙$TT$写了题解,我就只放下她题解好了/kel/kel/kel

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
#define il inline
#define gc getchar()
#define int long long
//#define int __int128
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i) const int N=;
int f[N][<<N],n,m;
bool gdgs=; il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
}
il bool pre(ri zt)
{
for(ri i=;i<m;)if(zt&(<<i)){if(i==m- || (!(zt&(<<(i+)))))return ;i+=;}else ++i;
return ;
}
il bool check(ri nw_zt,ri pre_zt)
{
// if(nw_zt==3 &&)
for(ri i=;i<m;)
{
if(nw_zt&(<<i))
{
if(pre_zt&(<<i))
{
// if(nw_zt==3 && pre_zt==13 && i==0)printf("???daraoleQAQ pre&2=\n");
if(i==m- || (!(nw_zt&(<<(i+)))) || (!(pre_zt&(<<(i+)))))return ;
i+=;
}
else ++i;
}
else{if(!(pre_zt&(<<i)))return ;++i;}
}
return ;
} il int dp()
{
ri tot=(<<m)-;memset(f,,sizeof(f));
// printf("tot=%lld\n",tot);
rp(s,,tot)if(pre(s))f[][s]=;//,printf("s=%lld\n",s);
rp(i,,n)rp(j,,tot)rp(k,,tot)
if(check(j,k))f[i][j]+=f[i-][k];//,printf("i=%lld j=%lld k=%lld\n",i,j,k);
return f[n][tot];
} main()
{
// freopen("j.in","r",stdin);freopen("j.out","w",stdout);
while(gdgs)
{
n=read(),m=read();
if(!n && !m)return ;if((n*m)&){printf("0\n");continue;}
if(n<m)swap(n,m);printf("%lld\n",dp());
}
return ;
}

$K$

一个非常显然的状压$dp$?显然考虑设$f_{i,j,k}$表示第$i$行然后这一行的状态是$j$上一行的状态是$k$时候的最多炮兵数,滚掉一维然后瞎转移下就好$QwQ$

然后一个小优化是,考虑给每个位置赋值,这个值指的就,这个位置附近最近能放炮兵的位置离它的距离,举个$eg$昂,就比如一个十字架,就会是这样儿的

0

1

0 1 2 1 0

1

0

转移啥的都差不多,但这样儿每行状态就可以压缩成一个三进制数辣,就可以省点儿空间$QwQ$

$upd:$,,,我枯了$sd\ gql$又双叒傻逼了,,,就法一的状态显然不需要那么设,,,因为已经预处理辣,所以$j$和$k$只要记录是哪一个就好,,,显然数量并不多,,,我开的100是够的$QwQ$

$over$,放个$code$鸭

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
#define il inline
#define lf double
#define fi first
#define sc second
#define gc getchar()
#define mp make_pair
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i) const int N=+,M=;
int n,m,f[N][M][M],zt[N],gdgs_num,as;
char str[M];
vector< pair<int,int> >gdgs; il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
}
il int cal(ri x){ri num=;rp(i,,m-)if(x&(<<i))++num;return num;}
il bool check(ri x){ri pre=-;rp(i,,m-)if(x&(<<i))if(i-pre>)pre=i;else return ;return ;}
il void pre(){rp(i,,(<<m)-)if(check(i))gdgs.push_back(mp(i,cal(i)));gdgs_num=gdgs.size();}
il bool jud(ri i,ri j,ri k){if(gdgs[i].fi&gdgs[j].fi || gdgs[j].fi&gdgs[k].fi || gdgs[i].fi&gdgs[k].fi)return ;return ;}
il void print(ri x){my(i,m-,)printf("%d",x&(<<i)?:);} int main()
{
freopen("k.in","r",stdin);freopen("k.out","w",stdout);
n=read();m=read();pre();
rp(i,,n){scanf("%s",str+);rp(j,,m)zt[i]=((zt[i]<<)+(str[j]=='H'));}
rp(i,,gdgs_num-)if(!(zt[]&gdgs[i].fi))f[][i][]=gdgs[i].sc;
rp(i,,n)
{
rp(j,,gdgs_num-)
{
rp(k,,gdgs_num-)
{
if(zt[i-]&gdgs[k].fi || zt[i]&gdgs[j].fi)continue;
rp(p,,gdgs_num-)
{
if(jud(j,k,p))f[i][j][k]=max(f[i][j][k],f[i-][k][p]+gdgs[j].sc);
}
}
}
}
rp(i,,gdgs_num-)rp(j,,gdgs_num-)as=max(as,f[n][i][j]);printf("%d\n",as);
return ;
}

$L$

似乎是水题鸭

只要不被题意杀就还是不太难的_(:з」∠)_(虽然$sd$如$gql$依然因为$get$错题意$WA$了一发嘤嘤嘤

昂所以还是先港下题意趴$QAQ$

大概就说,有$n$头奶牛,要覆盖$[1,T]$段,每个奶牛可以覆盖$[l_{i},r_{i}]$,然后问最少要多少头奶牛

$umm$不就是个贪心入门题,,,?任务安排问题还是叫什么,忘了_(:з」∠)_

就瞎拍个序瞎搞一通就好,贪心正确性过于显然不证辣$QAQ$

然后就放个代码就欧克克辣!

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
#define il inline
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i) const int inf=1e9;
int n,i,j,T,as,nw,nw_tr;
bool fd;
struct node{int st,en;}p[+]; il bool cmp(node x,node y){return x.st<y.st;}
il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
} int main()
{
n=read();T=read();
rp(i,,n)p[i]=(node){read(),read()};sort(p+,p++n,cmp);p[n+].st=inf;
rp(i,,n)
if(p[i].st<=nw_tr+)
{
if(p[i].en>nw)nw=p[i].en,fd=;
if(p[i+].st>nw_tr+ && fd)nw_tr=nw,++as,fd=;
}
if(nw_tr<T)printf("-1\n");else printf("%d\n",as);\
return ;
}

$M$

好气昂,,,我本来以为我做过这道题来着,,,然后找了半天并没有找到题解$or$做题记录/$kel$/$kel$/$kel$

所以还是写下这题趴$QAQ$

题意是港,有$k$个人给$n$块栅栏涂色,第$i$个人最多只能从$s_{i}$这个位置开始连续涂$l_{i}$块栅栏,可以一个也不涂,然后每个人涂一块的工钱是$p_{i}$.求最大工钱$QwQ$

显然考虑$dp$?设$f_{i,j}$表示第$i$个人涂到$j$这个位置时候最大工钱

转移也十分显然?$f_{i,j}=(f_{i-1,k}+p_{i}\cdot (j-k+1))_{max}$

然后这样儿就,是$O(K\cdot M^{2})$的

考虑单调队列优化下,就欧克辣$QwQ$

因为菜菜$gql$单调队列学得不太好,,,所以还是仔细港下$QAQ$,然后先港下,为了表示方便,就先把$f_{i,j}$暂时简化成$f_{j}$

考虑瞎变形一通呗$QwQ$,

$f_{j}=(f_{k}+p_{i}\cdot (j-k+1)){max}$

$f_{j}=p_{i}\cdot (j+1)+(f_{k}-p_{i}\cdot k)_{max}$

因为每次转移到时候可以当做是$i$和$j$是恒量,也就是说变量只有$k$,于是显然单调队列搞下后面那个$max$就做完辣$QwQ$

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
#define il inline
#define lf double
#define fi first
#define sc second
#define gc getchar()
#define mp make_pair
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i) const int K=+,N=+;
int n,k,que[N],head,tail,f[K][N];
struct node{int l,p,s;}nod[K]; il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
}
il bool cmp(node gd,node gs){return gd.s<gs.s;} int main()
{
// freopen("m.in","r",stdin);freopen("m.out","w",stdout);
n=read();k=read();rp(i,,k)nod[i].l=read(),nod[i].p=read(),nod[i].s=read();sort(nod+,nod++k,cmp);
rp(i,,k)
{
head=;tail=;
rp(j,max(,nod[i].s-nod[i].l),nod[i].s-)
{while(head<=tail && f[i-][que[tail]]-nod[i].p*que[tail]<=f[i-][j]-nod[i].p*j)--tail;que[++tail]=j;}
rp(j,,n)
{
f[i][j]=max(f[i-][j],f[i][j-]);
if(j>=nod[i].s){while(head<=tail && que[head]<j-nod[i].l)++head;if(head<=tail)f[i][j]=max(f[i][j],f[i-][que[head]]+nod[i].p*(j-que[head]));}
}
}
printf("%d\n",f[k][n]);
return ;
}
/*
有一个长度为n的[1,n]墙
有k位工人
第i位工可以刷包含si的长度小于等于li的区间,报酬为区间长度乘以pi
*/

$N$

先港下题意鸭$QwQ$

就说给定$n$个数$a_{1,...,n}$,然后要求分为若干块,使得每块的$sum\leq  m$,然后$\sum max_{min}$

先引入几个变量,$mx_{i,j}$表示$i$到$j$的$max$

显然考虑$dp$,,,$f_{i}=(f_{j}+mx_{j+1,i})_{min}$

因为$f_{i}$和$mx_{i,j}$显然都是递增的,然后因为有$m$的限制于是$j$也是递增的,于是考虑单调队列优化?

然后就做完咯,,,?

依然因为$gql$太菜了于是考虑详细港下趴$QAQ$

因为$f_{i}$是单增的,于是不难想到,如果在区间$[l,r]$内,满足$r$为最大值,则有$f_{l}+a_{r}\leq  f_{l+1}+a_{r}\leq ... \leq f_{r-1}+a_{r}$,所以一定是取$f_{l}$,也就是说,对于一段$l,r$,如果能满足$r$是其中的$max$,则会有取$l$时是最小的,换句话说,考虑构造一个$a_{i}$递减的序列$que_{j}$,每次只要把$que_{j}+1$拿出来就好(然后为了第一个数能表示出来所以要$que_{1}=0$,,,当然这种$just$小细节并不重要的辣$QwQ$

但这儿还有个问题要注意下昂$QwQ$,,,就,这里显然不能满足队列的队首就是最优的,,,队列里的每个数都能构成最优解来着$QAQ$,所以可以考虑再引入一个数据结构能维护一下这个$f_{i-1}+a_{i}$的$min$,然后还呲呲删除操作,显然考虑平衡树?然后用平衡树太麻烦辣,,,于是考虑用$set$就好了鸭$QwQ$

$over$?

挺妙的我$jio$得还,,,也许会$new$一篇文章专门给写个题解呢$QAQ$

对了记得开$ll$不然会$WA$嘤嘤嘤

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define il inline
#define lf double
#define fi first
#define sc second
#define gc getchar()
#define int long long
#define mp make_pair
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i) const int N=+;
int n,m,a[N],tail,head=,que[N],sum[N],nw,f[N];
multiset<int>s;
multiset<int>::iterator it; il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
} main()
{
// freopen("n.in","r",stdin);//freopen("n.out","w",stdout);
n=read();m=read();
rp(i,,n)
{
sum[i]=sum[i-]+(a[i]=read());if(a[i]>m)return printf("-1\n"),;
while(sum[i]-sum[nw]>m)++nw;
while(head<=tail && que[head]<=nw){if(head<tail)s.erase(s.find(f[que[head]]+a[que[head+]]));++head;}
while(head<=tail && a[que[tail]]<=a[i]){if(head<tail)s.erase(s.find(f[que[tail-]]+a[que[tail]]));--tail;}
que[++tail]=i;if(head<tail && i>que[tail-])s.insert(f[que[tail-]]+a[i]);
f[i]=f[nw]+a[que[head]];if(head<tail)f[i]=min(f[i],*s.begin());
}
printf("%lld\n",f[n]);
return ;
}

$O$

好像题目和$p$题差不多,,,?

那应该就差不多套路,,,不说辣$QwQ$

昂不过要$mk$下好像$get$了一个奇奇怪怪的方法$hhhh$

就,观察到这个$s$的范围是50以内的,相当于差不多一个批次执行时间的$1/200$?然后就说明暗示一个批次最多200个,,,限制下搜索分支就水过去辣,,,听起来很有趣的样子$hhhh$

$P$

语文不好选手没有人权$TT$,,,我我我我看了半天才看懂题,,,哭了$TT$

但是懒得解释题意辣,估计也只有我一个$sd$连题目都看不懂趴$QAQ$

然后直接看题嗷,显然考虑就直接设$dp$式了鸭,就$f_{i}$:第$j$个物品安排完了的最少花费

昂接下来为了表示方便,引入两个新变量,一个$st_{i,j}$表示$i$到$j$的所有物品的合计时间,还一个$sc_{i,j}$表示$i$到$j$的所有物品的合计花费

转移过于显然?$f_{i}=(f_{j}+st_{1,i}\cdot sc_{k+1,i}+s\cdot sc_{j,n})_{min}$

然后这样儿就$O(n^{3})$的?显然复杂度过不去,于是考虑斜率优化

明儿会写斜率优化专题的这儿就先咕辣_(:з」∠)_

$Q$

然后翻译的话洛谷上有,然而,洛谷的翻译简直有点儿莫名其妙,,,我理解了半天,,,虽然可能是我语文太差于是理解能力超差$QAQ$?不管反正就还是放个题目大意昂$QAQ$

大概就是说有$m$只猫分布在$n$座山上,现在能走$p$趟,每趟能带走所有能带走的猫,能带走的定义是,每只猫有一个对应的$t_{i}$,当到达这只猫所在山丘的时间$T_{i}\geq t_{i}$的时候就能带走第$i$只猫,然后到达山丘的时间是出发时间$T$加上从第一座山到第$j$座山的时间$D_{j}-D_{1}$,求最小化$\sum T_{i}-t_{i}$

鸭我发现我依然解释得很冗杂,,,

再简略一点好了?就给定$n,m,p,t_{m},D_{n}$,求最小化$\sum T_{j}+D_{i}-D_{1}-t_{i}$,其中$T_{j}$能有$p$个取值,且有$T_{j}+ D_{i} - D_{1} \geq t_{i}$

欧克反正这是我能达到的最简略辽,,,看题趴$QAQ$

既然是$dp$专题那就直接上手考虑$dp$趴,也不难想到,肯定先对猫按$t_{i}$排序,然后设$f_{i,j}$表示第$i$个人带走前$j$只猫的最小$as$,转移就枚举上一个人带到了第多少只,$f_{i,j}=(f_{i-1,k}+(j-k)\cdot t_{j}-sum_{k+1,j})_{min}$,昂这个$sum_{i,j}$是我引入的一个新变量,指的就$\sum_{k=i}^{j}t_{k}$

然后考虑时间复杂度,不难发现这样儿是$O(n^{2})$的,显然要优化,不难变形得$f_{i,j}=(f_{i-1,k}+sum_{k+1}-k\cdot t_{j})_{min}+j\cdot t_{j}-sum_{j}$,于是考虑斜率优化?

瞎写下斜率优化趴,,,我试着想了一下才发现我完全不会斜率优化昂,,,天呐$gql$实菜了$TT$

首先变形,后面为了表达方便,都压一位,即$f_{i,j}\rightarrow f_{j}$,然后把常数项先不管

瞎变形一通,设$g_{i}=sum_{i+1}+f_{i}$,于是得$k\cdot t_{j}+f_{j}=g_{k}$,考虑将$t_{j}$看做$K$,$g_{k}$看做$Y$,$k$看做$X$(,,,我错了我命名有点重,,,算了懒得改了大概能$get$就好$QAQ$

于是$f_{j}$就是$B$,于是就变成了,有若干条直线,斜率都是$t_{j}$,过点$(k,g_{k})$的最小截距(,,,大概是这么理解的,,,?具体解释咕不咕随缘,,,想起来了再更$QAQ$

然后就是个斜率优化经典题辣,到这儿还是不难辣$QAQ$

然后放个代码趴$QwQ$

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
#define il inline
#define int __int64
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i) const int N=+,M=+;
int n,m,p,sum[N],d[N],a[N],f[M][N],tp,hd,stck[N]; il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
}
void print(int x)
{
if(x>)print(x/);
putchar(''+x%);
} main()
{
// freopen("q.in","r",stdin);//freopen("q.out","w",stdout);
n=read();m=read();p=read();
rp(i,,n)d[i]=read()+d[i-];
rp(i,,m){ri x=read(),y=read();a[i]=y-d[x];}
sort(a+,a+m+);
sum[]=;rp(i,,m)sum[i]=sum[i-]+a[i];
rp(i,,m)f[][i]=i*a[i]-sum[i];
rp(i,,p)
{
stck[hd=tp=]=;
rp(j,,m)
{
while(hd<tp && f[i-][stck[hd+]]+sum[stck[hd+]]-(f[i-][stck[hd]]+sum[stck[hd]])<(stck[hd+]-stck[hd])*a[j])++hd;
f[i][j]=f[i-][stck[hd]]+(j-stck[hd])*a[j]-(sum[j]-sum[stck[hd]]);
stck[++tp]=j;
while(hd<tp-
&&
(f[i-][stck[tp]]+sum[stck[tp]]-(f[i-][stck[tp-]]+sum[stck[tp-]]))
*
(stck[tp-]-stck[tp-])
<
(f[i-][stck[tp-]]+sum[stck[tp-]]-(f[i-][stck[tp-]]+sum[stck[tp-]]))
*
(stck[tp]-stck[tp-])){--tp;stck[tp]=stck[tp+];}
}
}
print(f[p][m]);
return ;
}

(嗷对了,,,就,因为我之前$WA$了一次,就在$cf$上套了下数据,然后就$get$了第二组数据,还是算比较大样例辽,放上来存下如果$WA$了的可以拿这个数据测下$QwQ$


这是数据$QwQ$

$T$

因为是英文于是先放个题目大意趴$QAQ$

就说给定一个数字$n$,然后求按字典序排列后满足条件的第$k$大的数列长什么样儿,然后条件是说要求每个数两边的两个数要么都比它高要么都比它低,简单来说就,会成一个高低高低高低这样的排列

看到这个就会想到之前寒假的时候考试的那道题?1.22 T5,差不多想法,就预处理出这个点放这个数的方案数,然后就直接查询就好

具体这道题的话就预处理两个数组,$f_{i,j}$和$g_{i,j}$,分别表示(在这个长度为$i$的序列中)排名为$j$的数在第一个长度为$i$且是上升开头的方案数和第1个数的排名为$i$长度为$j$且是下降开头的方案数,做一通就好$QwQ$

然后就做完辣辣辣!

$upd$下关于转移中的一个小问题,就,为什么转移$g$的时候$k$是从$j$开始枚举而不是从$j+1$开始枚举的呢

这个是要结合$g$的意义看的,就因为它的$j$表示的是相对排名,然后要转移到$f_{i,j}$的话,就相当于要排除掉$j$这个数了,那么$[j+1,i]$的所有数的排名都会跌一位,也就是说原本排名是$j+1$的,在新的排名中就会是$j$了,因此其实从$j$开始枚举在$f_{i-1}$中的意义就相当于是从$j+1$开始枚举的$QwQ$

欧克我$jio$得现在的理解应该是最能理解的了,,,?如果还有问题在评论里港就好$kk$

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
#define il inline
#define int long long
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i) const int N=+;
int n,k,f[N][N],g[N][N],vis[N]; il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
}
il void pre()
{
f[][]=g[][]=;
rp(i,,)
rp(j,,i)
{
rp(k,,j-)f[i][j]+=g[i-][k];
rp(k,j,i-)g[i][j]+=f[i-][k];
}
}
il void output()
{
memset(vis,,sizeof(vis));
ri pre,prepre;
rp(i,,n)
{
ri cnt=;
rp(j,,n)
if(!vis[j])
{
ri tmp=k;++cnt;
if(i==)k-=f[n-i+][cnt]+g[n-i+][cnt];
else
{
if(j>pre && (i== || prepre>pre))k-=f[n-i+][cnt];
else if(j<pre && (i== || prepre<pre))k-=g[n-i+][cnt];
}
if(k<=){vis[j]=;printf("%lld ",j);prepre=pre;pre=j;k=tmp;break;}
}
}
printf("\n");
} main()
{
// freopen("t.in","r",stdin);freopen("t.out","w",stdout);
pre();ri T=read();
while(T--){n=read(),k=read();output();}
return ;
}

放个代码鸭$QwQ$

$upd:$

,,,$gql$傻逼石锤了$QAQ$

$O(n^{2})$简直不用脑子的优化我居然没想到,,,傻了吧唧地打了个$O(n^{3})$的傻逼玩意儿嘤嘤嘤

懒得改这道了,不过这题有个叫地精部落的双倍经验,我我我我只放下那题的$code$了昂$QwQ$

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
#define il inline
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i) const int N=+;
int n,k,f[][N],g[][N],mod,as;
bool gdgs=; il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
}
il int ad(ri x,ri y){return x+y>=mod?x+y-mod:x+y;}
il void work()
{
f[gdgs][]=g[gdgs][]=;
rp(i,,n)
{
gdgs^=;
f[gdgs][]=g[gdgs][]=;rp(k,,i-)g[gdgs][]=ad(g[gdgs][],f[gdgs^][k]);
if(i==n)as=(as+g[gdgs][])%mod;
rp(j,,i)
{
f[gdgs][j]=(f[gdgs][j-]+g[gdgs^][j-])%mod;g[gdgs][j]=((g[gdgs][j-]-f[gdgs^][j-])%mod+mod)%mod;
if(i==n)as=(as+f[gdgs][j]+g[gdgs][j])%mod;
}
}
} int main()
{
n=read();mod=read();work();printf("%d\n",as);
return ;
}

又一个$upd:$

神仙$hl$之前过来问了下$f_{i,j}$和$g_{i,i-j+1}$是不是相同的,然后我想了下之后感觉没想通,就没仔细想了

然后后面他去问了神仙$yyb$,然后$yyb$就港了一个只用开一个数组的方法,,,就用了上面那个思想

先放下这个方法,最后写过程趴$QwQ$

其实现在由我上面那个$upd$就能发现,现在关于这个$f_{i,j}$的式子就变成了,$f_{i,j}=f_{i,j-1}+g_{i-1,j-1}$

然后因为有$g_{i,j}=f_{i,i-j}$,于是有$f_{i,j}=f_{i,j-1}+f_{i-1,i-j+1}$

不太会证,大概数学归纳法可以,,,?感性理解不难发现确实如此$bushi$

嗷对了,这个还有一种理解方法,有时间写,然后还有一种组合数的方法,$xzy$学长还发到题解区了,,,但我还没看,,,有时间再搞趴$QAQ$

$U$

数位$dp$板子,,,没什么好说的鸭$QwQ$套路一波就完事辣,,,

懒得仔细写辣,,,大概就$dfs$一下,记录几个参数,瞎做一通,就欧克辣$QwQ$

$upd:$

啊我呆了嘤嘤嘤,,,

这题连$dfs$都不用来着,,,直接顺推是麻油问题的来着$QwQ$

不过我都打了$dfs$了还是打完趴$QAQ$

只是说下,我到时候放上来的代码会非常呆,因为直接顺推能解决的问题,被我搞成了一个$dfs$嘤嘤嘤

$over$

然后还有就是这题本来应该是试填法,,,?但我懒得打了就直接打了个二分$QwQ$

对了,这篇$code$有个$bug$,我知道怎么解决但不知道为什么,,,

就我前面有个$for$循环,是这么写的,"mx=lim?a[pos]:9;rp(i,0,mx){}",这样儿就是欧克的

但是我最开始是这么打的"rp(i,0,lim?a[pos]:9)",然后莫名其妙的$i$就感觉没约束似的不停地增增增增然后就$T$了,,,

我也不知道为什么,,,之前好像也遇到过来着,,,但一直不清楚为什么嘤嘤嘤

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
#define il inline
#define int long long
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i) const int N=;
int a[N],f[N][]; il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
}
il int power(ri gd,ri gs){ri ret=;while(gs){if(gs&)ret=1ll*ret*gd;gd=1ll*gd*gd;gs>>=;}return ret;}
il int solve(ri pos,ri state,rb lim)
{
if(!pos)return ;if(!lim && f[pos][state])return f[pos][state];
ri ret=,mx=lim?a[pos]:;rp(i,,mx){if(state== && i==)continue;ret+=solve(pos-,i==?state+:,i==a[pos] && lim);}
return lim?ret:f[pos][state]=ret;
}
il int pre(ri x){ri tmp=,tmpp=x;while(x){a[++tmp]=x%;x/=;}return tmpp-solve(tmp,,)+;} main()
{ri T=read();while(T--){ri x=read();ri l=,r=66666666666ll;while(l<r){ri mid=(l+r)>>;if(pre(mid)<x)l=mid+;else r=mid;}printf("%lld\n",l);}}

$V$

这题我没用$dp$辣,,,就感觉好像有什么规律,就瞎想了一下,发现$as$显然是$2^{n-1}+2^{n-1}\cdot  (n-1)/2$?瞎解释下就,首先是有$2^{n-1}$个数的,然后对于首位,必须是1,于是就是$2^{n-1}$,然后对于之后的,就都是有一半是1,于是就是$2^{n-1}/2\cdot (n-1)$,$over$

当然递推什么的也能做,,,懒得想了$QAQ$

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
#define il inline
#define int long long
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i) il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
} main()
{
// freopen("v.in","r",stdin);freopen("v.out","w",stdout);
ri T=read(),n,m;
while(T--){n=read();m=<<(n-);printf("%lld\n",m+m*(n-)/);}
return ;
}

随机推荐

  1. Jmeter json处理器

  2. oracle函数 months_between(d1,d2)

    [功能]:返回日期d1到日期d2之间的月数. [参数]:d1,d2 日期型 [返回]:数字 如果d1>d2,则返回正数 如果d1<d2,则返回负数 [示例] select sysdate, ...

  3. <肖申克的救赎>观后感

    肖申克的救赎主要讲述了银行家安迪在不健全的法律制度下被陷害进入了--鲨堡监狱,最后为了重见光明.追求自由,实现“自我救赎”的故事. 1.希望是件好东西,也许是世上最好的东西.好东西从来不会流逝. Ho ...

  4. @雅礼集训01/06 - T3@ math

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给出 n, m, x,你需要求出下列式子的值: \[\sum_{ ...

  5. 为更强大而生的开源关系型数据库来了!阿里云RDS for MySQL 8.0 正式上线!

    2019年5月29日15时,阿里云RDS for MySQL 8.0正式上线,使得阿里云成为紧跟社区步伐,发布MySQL最新版本的云厂商.RDS for MySQL 8.0 产品是阿里云推出的 MyS ...

  6. js判断浏览设备是 手机端,电脑端还是平板端

    console.log(navigator.userAgent); var os = function() { var ua = navigator.userAgent, isWindowsPhone ...

  7. 接管SpringBoot对Activiti的数据源自动配置

    SpringBoot的自动配置真的让人又爱又恨,但还是爱更多一点. SpringBoot想要帮我们自动配置好一切,但是有时候配置的却并不是我们需要的,甚至有时候会默默的坑我们. 我的项目是一个多数据源 ...

  8. SuperSocket获取会话的连接和断开事件

    关键字: 连接事件, 断开事件, OnSessionStarted,OnSessionClosed, NewSessionConnected, SessionClosed AppSession 的虚方 ...

  9. Codeforces Round #170 (Div. 1 + Div. 2)

    A. Circle Line 考虑环上的最短距离. B. New Problem \(n\) 个串建后缀自动机. 找的时候bfs一下即可. C. Learning Languages 并查集维护可以沟 ...

  10. laravel 常用文档

    [ Laravel 5.6 文档 ] 快速入门 —— 目录结构  laravel学院 http://laravelacademy.org/post/8657.html Laravel 的缓存系统    ...