zoukankan      html  css  js  c++  java
  • P7519 [省选联考 2021 AB 卷] 滚榜

    做完发现好简单,考场上还没想出来。。。

    题解

    考虑状压,相当于现在有多少队伍已经滚榜完毕。我们发现我们需要的条件有:上一次滚榜的题数(因为要满足递增),上一次加的题数(也要递增),已经使用过的题数(满足和为 (m) )。

    但是发现这样的状态我们好像存不下。

    首先我们可以发现,我们可以把上一次的题数改成上一次是哪支队伍,这样的话就可以通过队伍和 (b_i) 来推出上一次的题数。

    但是发现这样的话状态数是 (2^nnm^2) 的,转移是 (2^nn^2m^2) ,不太行。

    我们意识到这个 (m^2) 的地方着实不够优秀,我们需要找一点性质来把这个平方消去。

    先来看下我们现在的状态转移式子:

    f[i|(1<<(c-1))][c][max(k,a[j]+k-a[c])][d+max(k,a[j]+k-a[c])]+=f[i][j][k][d];
    

    我们可以发现对于这个 (max(k,a[j]+k-a[c])) ,我们可以将两边都减去 (k) ,同时将 (k) 对于 (d) 的贡献提前,我们就可以消去这个平方了。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=14,M=501;
    int n,m,a[N],cnt[1<<N];
    long long f[1<<N][N][M];
    signed main(){
    	cin>>n>>m;int tmp=0;
    	for(int i=1;i<=n;++i){
    		scanf("%d",&a[i]);
    		if(a[tmp]<a[i]) tmp=i;
    	}
    	for(int i=1;i<(1<<n);++i) cnt[i]=cnt[i>>1]+(i&1);
    	f[0][tmp][0]=1;
    	for(int i=0;i<(1<<n);++i){
    		for(int j=1;j<=n;++j){
    			for(int k=0;k<=m;++k){
    				if(!f[i][j][k]) continue;
    				for(int c=1;c<=n;++c){
    					if(i&(1<<(c-1))) continue;
    					int tmp=k+max(0,a[j]-a[c]+(j<c))*(n-cnt[i]);
    					if(tmp<=m) f[i|(1<<(c-1))][c][tmp]+=f[i][j][k];
    				}
    				// printf("%d %d %d %lld
    ",i,j,k,f[i][j][k]);
    			}
    		}
    	}
    	long long res=0;
    	for(int i=1;i<=n;++i){
    		for(int j=0;j<=m;++j)
    		res+=f[(1<<n)-1][i][j];
    	}
    	return printf("%lld
    ",res),0;
    }
    
  • 相关阅读:
    Java面向对象之封装静态
    分布式平台Spark环境的搭建
    高斯混合模型
    异常排除: 调用方未由服务进行身份验证
    HttpClient介绍和简单使用流程
    阿里短信服务的使用流程
    笔记工具选择
    特效图文制作
    语言基础(23):智能指针
    无线通信基础(一):无线网络演进
  • 原文地址:https://www.cnblogs.com/Point-King/p/14686626.html
Copyright © 2011-2022 走看看