51nod 1779 逆序对统计【状压DP】

28 篇文章 0 订阅
1 篇文章 0 订阅

Description

lyk最近计划按顺序做n道题目,每道题目都分为很多分数档次,lyk觉得这些题太简单了,于是它想到了一个好玩的游戏。

lyk决定将每道题目做出其中的某个分数,使得这n道题目的逆序对个数最多。

为了方便,假设共有m个分数档次,并且会给m个分数档次分配一个题目编号,表示该题目会出现这个分数档次。

题目保证每道题都存在至少一个分数档次。(例如样例中5道题目的分数分别是5,6,3,4,7,共有4个逆序对)

题解

很容易会想到状压DP。定义 f[i][j] 表示第 i 个分数档,j表示每道题是否被分配了某一个分数档的状态。预处理一下每个二进制数中有多少个1就可以实现O(1)转移了。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 106
#define maxm 1100006
using namespace std;
inline char nc(){
    static char buf[100000],*i=buf,*j=buf;
    return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;
}
inline int _read(){
    char ch=nc();int sum=0;
    while(!(ch>='0'&&ch<='9'))ch=nc();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
    return sum;
}
int n,m,a[maxn],g[maxm],f[2][maxm];
int main(){
    freopen("reverse.in","r",stdin);
    freopen("reverse.out","w",stdout);
    n=_read();m=_read();
    for(int i=1;i<=m;i++)a[i]=_read();
    for(int i=0;i<1<<n;i++){
        int x=i;
        while(x)g[i]+=x&1,x>>=1;
    }
    memset(f[0],192,sizeof(f[0]));
    f[0][0]=0;
    for(int i=1;i<=m;i++)
     for(int j=0;j<1<<n;j++)
        if((j>>(a[i]-1))&1)f[i&1][j]=max(f[1-(i&1)][j],f[1-(i&1)][j-(1<<(a[i]-1))]+g[(j>>a[i])<<a[i]]);
                      else f[i&1][j]=f[1-(i&1)][j];
    printf("%d\n",f[m&1][(1<<n)-1]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值