Description
lyk最近计划按顺序做n道题目,每道题目都分为很多分数档次,lyk觉得这些题太简单了,于是它想到了一个好玩的游戏。
lyk决定将每道题目做出其中的某个分数,使得这n道题目的逆序对个数最多。
为了方便,假设共有m个分数档次,并且会给m个分数档次分配一个题目编号,表示该题目会出现这个分数档次。
题目保证每道题都存在至少一个分数档次。(例如样例中5道题目的分数分别是5,6,3,4,7,共有4个逆序对)
题解
很容易会想到状压DP。定义
f[i][j]
表示第
i
个分数档,
代码
#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;
}