ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P7519 滚榜(状压 dp + 贪心)

2021-11-15 11:04:22  阅读:163  来源: 互联网

标签:int 状压 过题 滚榜 排行榜 队伍 need dp


目录

Description

Alice 围观了一场 ICPC 竞赛的滚榜环节。本次竞赛共有 nnn 支队伍参赛,队伍从 1n1 \sim n1∼n 编号,iii 号队伍在封榜前通过的题数为 aia_iai​。排行榜上队伍按照过题数从大到小进行排名,若两支队伍过题数相同,则编号小的队伍排名靠前。

滚榜时主办方以 bib_ibi​ 不降的顺序依次公布了每支队伍在封榜后的过题数 bib_ibi​(最终该队伍总过题数为 ai+bia_i + b_iai​+bi​),并且每公布一支队伍的结果,排行榜上就会实时更新排名。Alice 并不记得队伍被公布的顺序,也不记得最终排行榜上的排名情况,只记得每次公布后,本次被公布结果的队伍都成为了新排行榜上的第一名,以及所有队伍在封榜后一共通过了 mmm 道题(即 i=1nbi=m\sum_{i = 1}^{n} b_i = m∑i=1n​bi​=m)。

现在 Alice 想请你帮她算算,最终排行榜上队伍的排名情况可能有多少种。

State

\(1<=n<=13\)

\(1<=m<=500\)

\(0<=a_i<=10^4\)

Input

3 6
1 2 1

Output

5

Solution

由于最后只与排名有关,贪心考虑,每个队伍冲到榜首只花费最少的过题数,如果还有剩余,全放在最后一个人身上

这样 \(dp[s][i][k]\) : 表示状态 \(s\) 上为 \(1\) 的已经滚榜完毕,且 \(i\) 为当前榜首,总花费为 \(k\) 的种类数

\(dp\) 转移方程为 \(dp[s][i][k]=\sum dp[s\ xor \ (1 << i)][j][cost(i,j)]\)

最后答案为 \(\sum{dp[1..1][1-n][0-m]}\)


Code

const int M = 500 + 5;
const int S = (1 << 13) + 5;
const int N = 15 + 5;

    int n, m, k, _;
    int a[N];
    ll dp[S][N][M];

signed main()
{
    // IOS;
    while(~ sdd(n, m)){
        int maxx = -1;
        rep(i, 1, n){
            sd(a[i]);
            if(a[i] > a[maxx]){
                maxx = i;
            }
        }
        for(int i = 1; i <= n; i ++){
            int need = a[maxx] - a[i];
            if(maxx < i) need ++;
            if(need * n <= m){
                dp[1 << i - 1][i][need * n] = 1;
            }
        }
        int all = 1 << n;
        for(int s = 1; s < all; s ++){
            int popcount = __builtin_popcount(s);
            if(popcount == 1) continue;
            for(int i = 1; i <= n; i ++){
                if((s & (1 << i - 1)) == 0) continue;
                for(int j = 1; j <= n; j ++){
                    int now = s ^ (1 << i - 1);
                    if(i != j && (now & (1 << j - 1)) == (1 << j - 1)){
                        int need = a[j] - a[i];
                        if(i > j) need ++;
                        need = max(need * (n - popcount + 1), 0);
                        for(int k = need; k <= m; k ++){
                            dp[s][i][k] += dp[now][j][k - need];
                        }
                    }
                }
            }
        }
        ll ans = 0;
        for(int i = 1; i <= n; i ++){
            for(int k = 0; k <= m; k ++){
                ans += dp[all - 1][i][k];
                // dbg(dp[all - 1][i][k]);
            }
        }
        pll(ans);
    }
    return 0;
}

标签:int,状压,过题,滚榜,排行榜,队伍,need,dp
来源: https://www.cnblogs.com/Segment-Tree/p/15555090.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有