PKUSC 2018 随机算法

PKUSC 2018 随机算法

\[ made \ by \ Ameiyo \]



题目连接

用 $ f[i][s] $ 表示已经有 $ i $ 个点在排列里面,最大独立集的集合为 $ s $ ,这样的方案数。

对于当前不能加入最大独立集的点,在之后仍然不能加入,所以这些点可以被视为相同点,当做消耗品一样使用即可。

而可以加入的点,即加入后会使最大独立集变大的点,就直接放进 $ s $ 就行了。

#include <cstdio>
#include <cctype>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define ll long long
#define reg register
#define rep(i, a, b) for (reg int i = (a), i##end = (b); i <= i##end; ++i)
#define dep(i, a, b) for (reg int i = (a), i##end = (b); i >= i##end; --i)

template <typename _typer> inline _typer read() {
    _typer init = 0;
    char ch = getchar(), k = 0;
    for ( ; !isdigit(ch); ch = getchar()) k = (ch == '-');
    for ( ; isdigit(ch); ch = getchar())
        init = (init << 3) + (init << 1) + (ch ^ 48);
    return k ? -init : init;
}
const ll N = 25, INF = 1e9;
const ll M = (1 << 20), Mod = 998244353;

int n, m, G[N][N];
int tp[M], mk[N][M];
int f[N][M];

int Pow(int x, int k) {
    int ans = 1;
    for ( ; k > 0; x = 1ll * x * x % Mod, k >>= 1)
        ((k & 1) && (ans = 1ll * ans * x % Mod));
    return ans;
}

void Add(int &x, int y) { ((x += y) >= Mod && (x -= Mod)); }

int main() {
    n = read<int>(), m = read<int>();
    rep (i, 0, m - 1) {
        int x = read<int>() - 1, y = read<int>() - 1;
        G[x][y] = G[y][x] = true;
    }

    rep (i, 0, n - 1) tp[1 << i] = i, mk[i][0] = true;
    rep (i, 0, n - 1) rep (s, 1, (1 << n) - 1) if (!(s & (1 << i)))
        mk[i][s] = (mk[i][s & (s - 1)] && !G[i][tp[s & -s]]);

    f[0][0] = 1;
    // 不能放的点一直都不能放,所以可以算是一类点,就是把这部分处理掉就行了
    rep (i, 0, n - 1) rep (s, 0, (1 << n) - 1) if (f[i][s]) {
        reg int tmp = f[i][s], res = 0;
        rep (j, 0, n - 1) if (mk[j][s])
            ++res, Add(f[i + 1][s | (1 << j)], tmp);
        Add(f[i + 1][s], 1ll * tmp * (n - i - res) % Mod);
    }

    int Ans = 0, tot = 1, mx = 0;
    rep (i, 1, n) tot = 1ll * tot * i % Mod;
    rep (s, 0, (1 << n) - 1) if (f[n][s]) {
        int cnt = 0;
        for (int x = s; x > 0; x &= (x - 1)) ++cnt;
        if (cnt > mx) Ans = f[n][s], mx = cnt;
        else if (cnt == mx) Add(Ans, f[n][s]);
    }

//     cerr << Ans << endl;

    printf("%lld\n", 1ll * Ans * Pow(tot, Mod - 2) % Mod);
    return 0;
}

注意洛谷上卡内存, $ mk $ 数组开不了,但是 $ O(2 ^ n * n ^ 3) $ 可以过。。。



\[ in \ 2019.12.8 \]

原文地址:https://www.cnblogs.com/Ameiyo/p/12004561.html

时间: 2024-11-04 01:51:14

PKUSC 2018 随机算法的相关文章

Miller_Rabin算法(随机算法,判断一个数是否是素数)

1 const int S = 20;//随机算法判定次数,S越大,判错概率越小 2 LL pow_mod(LL a, LL b, LL mod) { // a^b%mod 3 LL ans = 1; 4 a = a % mod; 5 while(b) { 6 if(b & 1) { 7 ans = (ans * a) % mod; 8 } 9 a = ( a * a ) % mod; 10 b >>= 1; 11 } 12 return ans; 13 } 14 bool check

POJ 3318:Matrix Multiplication(随机算法)

http://poj.org/problem?id=3318 题意:问A和B两个矩阵相乘能否等于C. 思路:题目明确说出(n^3)的算法不能过,但是通过各种常数优化还是能过的. 这里的随机算法指的是随机枚举矩阵C的一个位置,然后通过A*B计算是否能够得到矩阵C相应位置的数,如果不等,就直接退出了,如果跑过一定的数量后能够相等,那么就可以判断这个矩阵C等于A*B的.第一次见这样的题目...有点新奇. 暴力算法: 1 #include <cstdio> 2 using namespace std;

微信红包随机算法

最近看了一篇文章,讲微信红包随机算法的.感觉很不错,所以自己实现了下,并进行了简单测试. 算法 算法很简单,不是提前算好,而是抢红包时计算: 红包里的金额怎么算?为什么出现各个红包金额相差很大?答:随机,额度在0.01和剩余平均值*2之间. 实现 实现上述算法的逻辑主要是: public static double getRandomMoney(RedPackage _redPackage) { // remainSize 剩余的红包数量 // remainMoney 剩余的钱 if (_red

加权随机算法

加权随机算法一般应用在以下场景:有一个集合S,里面比如有A,B,C,D这四项.这时我们想随机从中抽取一项,但是抽取的概率不同,比如我们希望抽到A的概率是50%,抽到B和C的概率是20%,D的概率是10%.一般来说,我们可以给各项附一个权重,抽取的概率正比于这个权重.那么上述集合就成了: {A:5,B:2,C:2,D:1} 方法一: 扩展这个集合,使每一项出现的次数与其权重正相关.在上述例子这个集合扩展成:{A,A,A,A,A,B,B,C,C,D}然后就可以用均匀随机算法来从中选取. 好处:选取的

权重随机算法的java实现

一.概述 平时,经常会遇到权重随机算法,从不同权重的N个元素中随机选择一个,并使得总体选择结果是按照权重分布的.如广告投放.负载均衡等. 如有4个元素A.B.C.D,权重分别为1.2.3.4,随机结果中A:B:C:D的比例要为1:2:3:4. 总体思路:累加每个元素的权重A(1)-B(3)-C(6)-D(10),则4个元素的的权重管辖区间分别为[0,1).[1,3).[3,6).[6,10).然后随机出一个[0,10)之间的随机数.落在哪个区间,则该区间之后的元素即为按权重命中的元素. 实现方法

随机算法 - HNU 13348 Finding Lines

Finding Lines Problem's Link: http://acm.hnu.cn/online/?action=problem&type=show&id=13348&courseid=0 Mean: 给你平面上1e5个点,让你判断是否可以找到一条直线,使得p%的点都在这条直线上. analyse: 经典的随机算法题. 每次随机出两个点,然后对n个点进行判断,看是否有p%的点在这条直线上. 关于随机算法正确性的证明: 每次随机一个点,这个点在直线上的概率是p,p最小为2

由抽奖软件想到的随机算法总结

整整三年没更新博客了,今天和女友聊天,聊到了博客,就回来看看. 最近接触到抽奖软件,下载的源码是http://download.csdn.net/detail/ghz_sd/6918125,在这里为开源软件作出贡献的人致敬,这个软件的作者a米山,是个非常好的人,耐心的帮我调试,他的算法很简单,就是纯粹的random,用的rand()函数,我给他提了个需求,写一个作弊类,实现的功能是:指定人的中奖概率提高,配置文件类似于这样: <xml> <win> <name='a' pro

中科院随机算法课程(孙晓明主讲)topic list

如题,列出<随机算法>课程的topic list,以记录和供有兴趣的朋友研究. Lession1:生日悖论.生日攻击.两个常用数学工具(马尔科夫不等式.切比雪夫不等式) Lession2:radom quick sort(hw).矩阵乘法判定.min(max())=max(min()).复杂性类(BPP/RP/CORP/ZPP) Lession3:证明BPP2/3=BPP0.99.ZPP<=RP^CORP.Game Tree Lession4:Balls and Bins Lession

歌曲播放的随机算法的探讨

对于音乐播放,最流行的有顺序播放,顺序循环播放,随机播放,单曲播放四种选项. 首先我以个人观点点评下目前常用的四种功能: 顺序播放:是一种很鸡肋的功能,为什么各大厂商都要做!感觉一般人都不会用的,播放一遍就停了,还不如做一个定时/定数停止播放的功能: 顺序循环播放:使用体验很不错,但是有个比较糟糕的问题是,让两首不相关的作品间产生了联系,导致了一首歌放完了,就已经知道了下首歌是什么了.或者当在其他地方听到了一首歌完了,脑中便浮现了自己音乐列表的下首歌了: 单曲播放:这个选项没什么可说的,动听歌曲