小清新签到题(DP)

传送门

然鹅我并不觉得这道题很清新rua

思维巧妙!(参考

对于第k小,我们可以这样考虑,若是第k小,那么比它小的方案应该是有k-1个。

在排列组合中,若固定i放在j位置,方案数是确定的,即:i固定在j位置,满足这个条件的序列的rank是在一个范围内的。

对于逆序对

常见思考方式是从小到大枚举数字,考虑对逆序对个数做出的贡献(从小到大插入,后插入不会对前插入造成影响)

设f[i][j]为i个数,j个逆序对的方案数,可得转移方程为

f[i][j]=f[i-1][j]+f[i-1][j-1]+……+f[i-1][j-i+1]

(就相当于给一个比序列中所有数都大的数,让你往里插。)

可用前缀和优化(注意是一层一层的前缀和而不是二维前缀和)

然后我们可以一个个从后往前放数,枚举每一位可以放什么数(1~n),统计放这个数所造成的贡献num,以及之前可以放的数(但因为达不到k而被放弃)的方案数tmp。(但tmp在算这一次放的数是否达到逆序对要求时要加上)

注意f数组容易爆LL,但k的范围是1e13,所以超过了就改为k+1即可。

#include<bits/stdc++.h>
#define LL long long
#define N 303
using namespace std;
LL read()
{
    LL x=0,f=1;char s=getchar();
    while(s<‘0‘||s>‘9‘){if(s==‘-‘)f=-1;s=getchar();}
    while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();}
    return x*f;
}
LL f[N][N*N],s[N][N*N];//f[i][j]i个数j个逆序对的方案数,s前缀和
int ans[N],vis[N];
void init(LL n,LL k,LL x)
{
    f[0][0]=1;
    for(int i=0;i<=x;++i)s[0][i]=1;//注意逆序对数可以取到0
    for(int i=1;i<=n;++i)
    {
        for(int j=0;j<=x;++j)
        {
            int l=max(0,j-i+1),r=j;
            LL tmp=(l==0)?s[i-1][r]:(s[i-1][r]-s[i-1][l-1]);
            f[i][j]=min(tmp,k+1);
            s[i][j]=f[i][j]+s[i][j-1];
        }
    }
}
int main()
{
    LL n=read(),k=read(),x=read();
    init(n,k,x);
//    for(int i=1;i<=n;++i)
//      for(int j=1;j<=x;++j)
//        printf("%lld\n",f[i][j]);
    for(int i=n;i>=1;--i)
    {
        LL tmp=0;
        for(int j=1;j<=n;++j)
        {
            if(vis[j])continue;
            int num=j-1;//对逆序对个数最多产生的贡献,也就是比它小的都在它后面这种情况
            for(int l=1;l<j;++l)num-=vis[l];
            if(tmp+f[i-1][x-num]>=k)
            {
                ans[n-i+1]=j;//可以确定这个位置填j
                vis[j]=1;x-=num;k-=tmp;
                break;
            }
            tmp+=f[i-1][x-num];//!!!
        }
    }
    for(int i=1;i<=n;++i)
      printf("%d ",ans[i]);
} 

原文地址:https://www.cnblogs.com/yyys-/p/11360156.html

时间: 2024-10-12 08:25:47

小清新签到题(DP)的相关文章

[Luogu3676]小清新数据结构题

题面戳我 题意:给一棵树,树上有点权,每次操作为修改一个点的点权,或者是询问以某个点为根时,每棵子树(以每个点为根,就有n棵子树)点权和的平方和. \(n\le2*10^5\),保证答案在long long范围内 sol 我们设\(s_i\)表示以\(p\)为整棵树的根时,以\(i\)为根的子树的点权和.设\(Sum\)表示所有点的点权和,即\(Sum=\sum_{i=1}^{n}val_i\). 所以这道题给出\(p\),就是要你求\(\sum_{i=1}^{n}s_i^2\). 我们先看\(

【luoguP3676】 小清新数据结构题 推式子(LCT维护)

挺有趣的一个数据结构题,不必用 LCT 维护,只不过 LCT 比较好写 ~ code: #include <cstdio> #include <string> #include <cstring> #include <algorithm> #define N 200008 #define ll long long #define lson s[x].ch[0] #define rson s[x].ch[1] using namespace std; ll a

【刷题】洛谷 P3676 小清新数据结构题

题目背景 本题时限2s,内存限制256M 题目描述 在很久很久以前,有一棵n个点的树,每个点有一个点权. 现在有q次操作,每次操作是修改一个点的点权或指定一个点,询问以这个点为根时每棵子树点权和的平方和. (题目不是很好懂,没看太懂的可以看看样例解释) 输入输出格式 输入格式: 第一行两个整数n.q. 接下来n-1行每行两个整数a和b,表示树中a与b之间有一条边,保证给出的边不会重复. 接下来一行n个整数,第i个整数表示第i个点的点权. 接下来q行每行两或三个数,如果第一个数为1,那么接下来有两

Luogu 3676 小清新数据结构题

推荐博客: http://www.cnblogs.com/Mychael/p/9257242.html 感觉还挺好玩的 首先考虑以1为根,把每一个点子树的权值和都算出来,记为$val_{i}$,那么在所有操作都没有开始的时候(以$1$为根的)$ans_{1} = \sum_{i= 1}^{n}val_{i}^{2}$ 考虑到一个修改的操作只会对修改的点$x$到根($1$)链上的点产生影响,那么一次修改只要修对这条树链上的点增加$v - a_{x}$(假设修改后的值为$v$)就好了. 链剖之后线段

Luogu3676 小清新数据结构题 动态点分治

传送门 换根类型的统计问题动态点分治都是很好做的. 设所有点的点权和为$sum$ 首先,我们先不考虑求$\sum\limits_i s_i^2$,先考虑如何在换根的情况下求$\sum\limits_i s_i$. 考虑一个点$i$会被统计多少次,显然是$dep_i+1$,那么$\sum\limits_i s_i = \sum\limits_i (dep_i+1) \times val_i = \sum\limits_i dep_i \times val_i + sum$. $\sum\limit

lp3676 小清新数据结构题

传送门 Description 有一棵\(n\)个点的树,每个点有一个点权. 现在有\(q\)次操作,每次操作是修改一个点的点权或指定一个点,询问以这个点为根时每棵子树点权和的平方和. Solution 我们设\(Sum=\sum_{i=1}^{n} w_i\),\(s_i\)表示\(i\)子树的权值和 发现不管根是哪个节点,\(W=\sum_{i=1}^n s_i(Sum-s_i)\)都是一个定值 因为它相当于对于每条边连接的两个联通块的"点权和的积"的和 所以,我们要求的\(\su

P3694 邦邦的大合唱站队/签到题(状压dp)

P3694 邦邦的大合唱站队/签到题 题目背景 BanG Dream!里的所有偶像乐队要一起大合唱,不过在排队上出了一些问题. 题目描述 N个偶像排成一列,他们来自M个不同的乐队.每个团队至少有一个偶像. 现在要求重新安排队列,使来自同一乐队的偶像连续的站在一起.重新安排的办法是,让若干偶像出列(剩下的偶像不动),然后让出列的偶像一个个归队到原来的空位,归队的位置任意. 请问最少让多少偶像出列? 输入输出格式 输入格式: 第一行2个整数N,M. 接下来N个行,每行一个整数a_i(1\le a_i

QDUOJ 来自xjy的签到题(bfs+状压dp)

来自xjy的签到题 Description 爱丽丝冒险来到了红皇后一个n*n大小的花园,每个格子由'.'或'#'表示,'.'表示爱丽丝可以到达这个格子,‘#’表示爱丽丝不能到达这个格子,爱丽丝每1分钟可以移动到非'#'的相邻格子(与当前所在格子具有公共边).花园下面有m个隧道,每个隧道有一个出口和一个入口.当爱丽丝到达隧道的入口时,她可以选择(也可以不选择)进入隧道入口,并通过隧道一次,然后立即(不花费时间)出现在隧道出口.爱丽丝一开始可以降临在花园的任何地方.有好奇心的爱丽丝想知道,她通过所有

小象和老鼠 DP

小象和老鼠 DP \(N*M\)的网格图,格子\((i,j)\)有\(A_{i,j}\)个老鼠,问小象从左上角\((1,1)\)走到右下角\((N,M)\)看到的最少老鼠.小象可以看见老鼠,当且仅当老鼠的位置\((x2,y2)\)满足\(|x1-x2|+|y1-y2|\le1\). 比较有意思的一道DP题,还是比较简单.我们发现如果直接设\(f[i][j]\)跑会导致一些格子重复计算,所以我们可以设\(f[i][j][0]\)表示到位置\((i,j)\)时最少看到的老鼠数量,并且当前状态是从上面