[容斥原理][Meet-in-middle][Matrix-Tree定理] SRM551 Div1 Hard SweetFruits

Topcoder SRM551 Div 1 1000:SweetFruits(矩阵树+容斥) 题解: 考虑枚举哪几个水果是甜的。 发现如果枚举的数量一样,那么对答案的贡献也一样。那么可以根据枚举数量来一起处理。 枚举完数量kkk之后,甜与半甜的不连边,然后跑矩阵树,得到小等于kkk的甜的水果的生成树数量。 因为之前的已经处理过,直接减掉就好。 注意减去的时候要减去组合数,因为这k个中任意组合都会被统计。 之后问题变为了数量kkk, 值小等于vvv的个数,这个直接折半就行了。 ... 阅读详情

SolutionSolution

将原问题分成两个子问题。

  • 从所有甜的水果中选出kk个水果作为真甜的,要求他们甜度之和不超过maxSweetness的方案数cntkcntk
  • 令nn为甜的水果数目,求出组成的树的方案数treek使得nn个甜的水果中恰有k个水果为真甜的。
    ans=∑k=0ncntktreekans=∑k=0ncntktreek

第一个问题Meet-in-middle可以O(2n2n)O(2n2n)解决。
第二个问题让真甜的水果和任意水果连边,让半甜的水果只能和不甜的水果连边,苦的水果和任意水果连边。这样求出其生成树的方案数Tk=∑ki=0(ki)treeiTk=∑i=0k(ki)treei。二项式反演一下就能求到treek=∑ki=0(−1)k−i(ki)Titreek=∑i=0k(−1)k−i(ki)Ti了。时间复杂度O(n4)O(n4)。

// BEGIN CUT HERE

// END CUT HERE
#line 5 "SweetFruits.cpp"
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 90;
const int M = 21;
const int MOD = 1000000007;

int lim, n, m, ans;
int a[N];
int tree[N], T[N];
int C[N][N];
vector<int> l1[N], l2[N];
struct Matrix {
    int a[N][N];
    inline int *operator [](int x) {
        return a[x];
    }
    inline void Clear(void) {
        memset(a, 0, sizeof a);
    }
};
Matrix A;

inline void Add(int &x, int a) {
    x = (x + a) % MOD;
}
inline int Pow(int a, int b) {
    int c = 1;
    while (b) {
        if (b & 1) c = (ll)c * a % MOD;
        b >>= 1; a = (ll)a * a % MOD;
    }
    return c;
}
inline int Inv(int x) {
    return Pow(x, MOD - 2);
}
inline int Det(Matrix a, int n) {
    int f = 0;
    for (int i = 1; i <= n; i++) {
        int k = 0;
        for (int j = i; j <= n; j++)
            if (a[j][i]) { k = j; break; }
        if (i != k) {
            for (int j = i; j <= n; j++)
                swap(a[i][j], a[k][j]);
            f ^= 1;
        }
        for (int j = i + 1; j <= n; j++) {
            int t = (ll)Inv(a[i][i]) * a[j][i] % MOD;
            for (int k = i; k <= n; k++)
                Add(a[j][k], MOD - (ll)t * a[i][k] % MOD);
        }
    }
    int res = 1;
    for (int i = 1; i <= n; i++)
        res = (ll)res * a[i][i] % MOD;
    if (f) res = (MOD - res) % MOD;
    return res;
}

class SweetFruits {

public:
    inline void Pre(void) {
        int mid = n >> 1, U;
        U = 1 << mid;
        for (int S = 0; S < U; S++) {
            int c1 = 0, co = 0;
            for (int i = 1; i <= mid; i++)
                if ((S >> i - 1) & 1) {
                    ++c1; co += a[i];
                }
            l1[c1].push_back(co);
        }
        U = 1 << (n - mid);
        for (int S = 0; S < U; S++) {
            int c1 = 0, co = 0;
            for (int i = mid + 1; i <= n; i++)
                if ((S >> i - mid - 1) & 1) {
                    ++c1; co += a[i];
                }
            l2[c1].push_back(co);
        }
        for (int i = 0; i <= mid; i++)
            sort(l1[i].begin(), l1[i].end());
        for (int i = 0; i <= n - mid; i++)
            sort(l2[i].begin(), l2[i].end());
        for (int i = 0; i <= n + m; i++) {
            C[i][0] = 1;
            for (int j = 1; j <= i; j++)
                C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
        }
    }
    inline int Count(int k) {
        int res = 0;
        for (int x = 0; x <= k; x++) {
            int y = k - x, p2 = l2[y].size() - 1;
            for (int u: l1[x]) {
                while (~p2 && l2[y][p2] + u > lim) --p2;
                Add(res, p2 + 1);
            }
        }
        return res;
    }
    inline void AddEdge(int from, int to) {
        A[from][to] = MOD - 1; A[to][from] = MOD - 1;
        ++A[from][from]; ++A[to][to];
    }
    inline int Tree(int k) {
        A.Clear();
        for (int i = 1; i <= n + m; i++)
            for (int j = i + 1; j <= n + m; j++)
                if (j <= k || j > n)
                    AddEdge(i, j);
        T[k] = Det(A, n + m - 1);
        for (int i = 0; i <= k; i++)
            if ((k - i) & 1) Add(tree[k], MOD - (ll)C[k][i] * T[i] % MOD);
            else Add(tree[k], (ll)C[k][i]* T[i] % MOD);
        return tree[k];
    }
    int countTrees(vector <int> sweetness, int maxSweetness) {
        lim = maxSweetness;
        for (int x: sweetness)
            if (x >= 0) a[++n] = x;
            else ++m;
        Pre(); ans = 0;
        for (int k = 0; k <= n; k++)
            Add(ans, (ll)Count(k) * Tree(k) % MOD);
        return ans;
    }

    // BEGIN CUT HERE
public:
    void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); if ((Case == -1) || (Case == 4)) test_case_4(); }
private:
    template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); }
    void verify_case(int Case, const int &Expected, const int &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } }
    void test_case_0() { int Arr0[] = {1, 2, -1, 3}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 3; int Arg2 = 3; verify_case(0, Arg2, countTrees(Arg0, Arg1)); }
    void test_case_1() { int Arr0[] = {1, 2, -1, 3}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 5; int Arg2 = 7; verify_case(1, Arg2, countTrees(Arg0, Arg1)); }
    void test_case_2() { int Arr0[] = {-1, -1, 2, 5, 5}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 6; int Arg2 = 20; verify_case(2, Arg2, countTrees(Arg0, Arg1)); }
    void test_case_3() { int Arr0[] = {2, 6, 8, 4, 1, 10, -1, -1, -1, -1}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 15; int Arg2 = 17024000; verify_case(3, Arg2, countTrees(Arg0, Arg1)); }
    void test_case_4() { int Arr0[] = {1078451, -1, 21580110, 8284711, -1, 4202301, 3427559, 8261270, -1, 16176713,
                                                                         22915672, 24495540, 19236, 5477666, 12280316, 3305896, 17917887, 564911, 22190488, 21843923,
                                                                         23389728, 14641920, 9590140, 12909561, 20405638, 100184, 23336457, 12780498, 18859535, 23180993,
                                                                         10278898, 5753075, 21250919, 17563422, 10934412, 22557980, 24895749, 7593671, 10834579, 5606562}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 245243285; int Arg2 = 47225123; verify_case(4, Arg2, countTrees(Arg0, Arg1)); }

    // END CUT HERE


};

// BEGIN CUT HERE
int main(void) {
    SweetFruits ___test;
    ___test.run_test(-1);
    system("pause");
}
// END CUT HERE
最新小旋风蜘蛛池X6.21解密版+绕过授权带教程 介绍: 1.站群管理:用你的域名在这里添加网站 2.站点优化:站点互链,内容优化 2.系统设置:开启蜘蛛池 3.采集管理(可开启自动采集) 4.缓存设置:推荐开启tkd缓存 其他的用户根据自己的实际情况后台进行配置,通常以下: 1.后台首页(这里显示系统的大致概况) 2.系统设置:蜘蛛池的基本设置(访问开关、跳转、统计等等) 3.站群管理: 1.网站管理(用你的域名在这里添加网站) 2.模型管理(可构建不同类型站点:电影、文章、论坛等等) 3.TKDB调用模板(即:title、keywords、descri 阅读详情

相关推荐

从亚稳态到流片失败:SpyGlass CDC在5G芯片设计中的避坑指南

本文深入探讨了在复杂5G芯片设计中,如何利用SpyGlass CDC工具构建高效的时钟域交叉验证流程,以避免因亚稳态问题导致的流片失败。文章结合实战经验,详细解析了从约束编写、时钟复位完整性检查到层次化验证和特殊场景处理的全过程,并强调了精准的检查约束是确保验证有效性的基石,旨在帮助设计团队安全跨越异步时钟域的雷区。

weixin_29168153的博客 444

CF - 525E - meet-in-middle

题目链接:点击打开链接 解题思路:解法很多,这里说一下怎么用meet-in-middle来做,跟分治很像,就是预先把一半的数据里面的所有结果和全都枚举取来,枚举出来后排个序,然后枚举另一半去二分找相差值,这样就可以用2^(n/2)*log(2^(n/2))找出所有的解。 #include<bits/stdc++.h> using namespace std; type...

过路人丶的博客 428

【详细图文】使用MobaXterm的SSH功能远程连接服务器,并创建pytorch环境,使用yolov8训练数据集

使用MobaXterm的SSH功能远程连接服务器,并创建pytorch环境,使用yolov8训练数据集,以及MobaXterm使用介绍和linux基础命令介绍。

qq_62844901的博客 3384

浅谈Meet in the middle

Meet in the middle 算法是一种在搜索类问题中常用的技巧 顾名思义这种算法就是同时从两个点往中间搜索,直到碰头为止 看两个图 我们假设一个情景,图一中标红的两个点分别是起点和终点,现在我们要找出一条从起点到终点的路径。 按照传统的BFS思路,我们从上方的起点开始往下搜索,每次拓展相邻的节点。 这样我们就需要遍历大部分的节点才能找到答案,搜索树十分庞大 而当...

qq_43398760的博客 3140

使用Tansformer分割三维腹部多器官--UNETR实战

不会 transformer 没关系,本教程开箱即用。Tina姐总算对transformer下手了,之前觉得难,因为刚开始学序列模型的时候就没学会。然后就一直排斥学transformer。这两周没什么事,加上MONAI有现成的教程,就打算先跑通后,再学理论。然后,顺利的跑通了代码,再学了一周理论,发现它也不过如此嘛,入门还是很容易的。有同学想了解的transformer的话,可以先看完这个实战教程,如果感兴趣,后续会出一个transformer入门路线。利用纯Transformers作为编码器来学习输入量的

Tina姐的博客 1万+

国产麒麟系统各版本镜像下载

以上各链接均为迅雷下载,禁止商业用途!

2302_79474754的博客 6126

dfs复习

h(n) 是启发式函数,用于估计从当前节点n到目标节点的代价。不用担心这样会导致过于高的复杂度,其实认真思考下就会发现如果高度为dep,当我们下次搜第dep+1层的时候,叶子结点的数量的数量级和之前1~dep层加起来差不多,所以这样的优化有时候效果是很突出的。先去搜索前面N/2个礼物,获得其对应的重量集合,然后对后面的N/2个进行搜索,根据获得的重量在前面的重量集中使用二分查找获得最优值。同样是迭代加深+A*,这里的每次的操作最多给我们带来1的改变,所以估价函数就是中间的方格中不符合的数目。

2401_84910613的博客 772

数值计算之 插值法(4)切比雪夫零点插值

数值计算之 插值法(4)切比雪夫零点插值前言插值点选取第一类切比雪夫多项式拉格朗日插值多项式的余项切比雪夫零点插值后记 前言 上篇插值法讨论了多项式插值的解,以及龙格现象。本篇将介绍一种在抽取节点时有效降低龙格现象的方法——切比雪夫零点插值。 插值点选取 插值多项式阶数较高时,在取值空间均匀取点,容易出现龙格现象。 即区间边缘的插值结果与原函数差异很大,而区间中央的插值结果相对较好。这表明,高阶多项式插值对区间中央的节点拟合好,而对两端节点拟合效果差。 自然而然会想到,在两端多采样一些节点,在中间少采样一

qq_41035283的博客 1万+

Prime Gift(prime)

Prime Gift(prime) Prime Gift(prime) 题目描述   Jyt有nn个质数,分别为p1,p2,p3…,pnp1,p2,p3…,pn。 她认为一个数xx是优秀的,当且仅当xx的所有质因子都在这nn个质数中。 她想知道第kk大的优秀的数是多少。保证答案不超过10181018。 ...

liankewei的博客 215

uniapp - 超详细 H5 网页利用 uni.downloadFile 下载 URL 文件流并调用浏览器下载功能效果,前台通过请求后端接口获取文件并下载保存到本地(支持电脑PC与手机移动端H5)

uniapph5网页下载文件,uniapp网站下载文件流,uniapp的移动端h5实现接口url文件下载,uniapph5页面在浏览器中如何下载指定url文件流文件并保存到本地,uniapp移动端h5调用后端接口保存文件到本地,uniapph5通过下载后获得临时路径怎么让浏览器弹出下载,uniapp怎么请求接口下载到文件,得到Blob临时路径对象后如何下载到本地,浏览器怎么下载blob对象,uniapp二进制文件流下载,uniapph5中的文件流下载和指定的url下载详细教程,uniappapp移

🏆 前端领域优质创作者 1万+

智启古文字新章:AI、ML与大数据驱动的知识图谱构建

摘要:本文聚焦AI、ML与大数据驱动的古文字知识图谱构建。开篇点明古文字研究困境,凸显技术革新迫切性。随后阐释AI、ML、大数据基础概念,详解其在图谱构建里的数据采集、知识抽取、关系挖掘运作流程,穿插线性代数、概率论等数学原理。实战展示殷商甲骨文图谱搭建全程,含数据处理、模型训练。还探讨跨模态融合等前沿挑战应对,兼述技术融合衍生的教育科普革新、伦理文化责任、国际合作交流,勾勒古文字数字永生的长远愿景。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1614

1268 和为K的组合 Meet in mid二分思路

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1268&judgeId=193772 给出n = 20个数,问其是否有和为k的情况 分两段,用O(2^(n / 2))复杂度维护出每一段的所有情况。 然后枚举第一段,二分判断第二段是否也有k - first #include <cstdio&g...

weixin_30914981的博客 140

C# + YOLO 实时摄像头检测:Emgu CV + ONNX Runtime,30FPS+ 流畅运行

很多教程只给“单张图片推理”代码,一上摄像头就卡成 PPT(<5 FPS)。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 215

【矩阵树定理+容斥】Topcoder SRM 551 DIV1 Hard SweetFruits (TC12141)

【前言】 吐槽一下TC的交代码,在SRMs的练习模式那里交每提交一次分数上限会少一点,于是根本不知道过没过。在VJ上交才知道过了。 当然可能是我太菜了。 【题目】 Topcoder 给定nnn个权值,要么非负,要么为−1-1−1,你现在可以用n−1n-1n−1条边连接这些权值得到一棵树。我们称一个权值是有用的当且仅当它它和至少一个非负权值相连且它本身不为负,这棵树的权值为所有有用的权值之和。 求有...

MEET YOU FIRST TIME 335

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

[meet in middle 矩阵树定理 容斥原理] SRM 551 div1 SweetFruits

集训队论文传送门大概就是我们先用meet in middle求出有恰好k个真甜的方案数 然后我们求这些东西的生成树个数 乘在一起的和就是答案 我们让真甜连真甜 真甜连不甜 假甜连不甜 不甜连不甜 跑一发矩阵树定理 这样只能保证这些真甜的某个子集是真甜 那么我们需要用 0~k-1 的简单容斥一下// BEGIN CUT HERE #include<conio.h> #include<sstr

雯舞 754

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

[矩阵树定理 容斥 meet in middle] Topcoder SRM 551 DIV1 Hard. SweetFruits

枚举最后的树中有多少个是truly sweet的 答案就是 ∑i=0nfi×gi \sum_{i=0}^n f_i\times g_i 其中,fif_i 表示选出 ii 个水果使其价值和不超过Limit的方案数 gig_i 是有 ii 个truly sweet的生成树个数fif_i 可以meet in middle 设图中前 ii 个点是truly sweet, i+1i+1 到 kk 是s

CE玩家 712

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

srm 551

资瓷点此阅读QvQ250Description题意:一个长度最多5050的字符串,每次操作可以交换相邻的两个字符,问,经过最多MaxSwapsMaxSwaps次交换之后,最多能让多少个相同的字符连起来Solution枚举一个字符,让其他字符往这里即可,取最小即可Code#include <bits/stdc++.h> using namespace std; #define pb push_back

mlzmlz95的专栏 471

[矩乘优化DP] Topcoder SRM550 DIV1 Hard. ConversionMachine

每个位置显然是先变成正确的,然后进去若干循环这样就可以算出最多进行多少轮变换,令 fi,j,kf_{i,j,k} 表示进行了 ii 轮变换,有 jj 个位置差一次变换, kk 个位置差两次变换直接DP肯定不行,可以用矩乘优化// BEGIN CUT HERE // END CUT HERE #include <vector> #include <list> #include <map>

CE玩家 725

TC SRM 551 div2 题解

转载请注明出处,谢谢 http://blog.youkuaiyun.com/ACM_cxlove?viewmode=contents           by---cxlove 终于在TC过了两题,可惜第三题看错了题目。 250pt:只需要判断有几种颜色即可。 class ColorfulBricks{ public: int countLayouts(string bricks){ bool

窝不是爱酱,喵~~~~ 2361

树状数组的三种操作

直接贴代码一、改点求段 namespace BIT { #define N 100000 #define lowbit(a) ((a)&(-a)) int c[N],num; void init(int n){num=n;} inline void add(int x,int a) { int xx=x;

Vectorxj的博客 1423

[NTT][DP][树链剖分][分治] LOJ #6289. 花朵

SolutionSolutionSolution fu,0/1,ifu,0/1,if_{u,0/1,i}表示uuu子树中选了iii个点,uuu选不选的答案。 转移显然就是一个卷积的形式。 考虑重链剖分。 先把轻儿子卷到根,这样只需要考虑重链。 再考虑重链上的DP。 考虑头尾选不选gu,0/1,0/1gu,0/1,0/1g_{u,0/1,0/1}。这也是个卷积,可以分治+FFT。 #i...

Vectorxj的博客 1012

[多项式ln][多项式exp][多项式求幂][生成函数][DP][FNT] BZOJ 3684: 大朋友和多叉树

SolutionSolutionSolution 把DP写成生成函数的形式。f(x)=x+∑d∈Dfd(x)f(x)=x+∑d∈Dfd(x)f(x)=x+\sum_{d\in D}f^d(x)设g(f(x))=xg(f(x))=xg\big(f(x)\big)=x,有g(f(x))g(x)==f(x)−∑d∈Dfd(x)x−∑d∈Dxdg(f(x))=f(x)−∑d∈Dfd(x)g(x)=x−∑...

Vectorxj的博客 923

[构造]AGC005C - Tree Restoring

DescriptionDescription给出一个数组aa。 要求构造一颗树,使节点uu距离最远的点的距离为aua_u。SolutionSolution这颗树的直径d=maxni=1aid=max_{i=1}^n{a_i}。 可以通过对dd奇偶性的分类讨论,把在直径上节点的值计算掉。 然后其他的点的值一定大于等于在直径上的点的值的最小值。 等号可不可取也是要分奇偶性讨论的。#include

Vectorxj的博客 633

BZOJ 4034 [树链剖分][线段树]

如果在一棵树上求两个节点间路径的最大值最小值权值和等等,并且还支持修改某一段路径的权值等等,光靠线段树是不够的,这是就需要树链剖分,将一棵树转化成线段,然后求解。For instance, BZOJ 4034: [HAOI2015]T2 Description 有一棵点数为 N 的树

Vectorxj的博客 623

[后缀自动机][树上启发式合并] LOJ #6041. 「雅礼集训 2017 Day7」事情的相似度

SolutionSolutionSolution O(nn−−√logn)O(nnlog⁡n)\mathcal{O}(n\sqrt n\log n)的莫队连500005000050000都过不了qwq。 %%%gjghfd gjghfd教我SAM+树上启发式合并的做法。 每两个后缀的贡献会在LCA处统计到。 一个暴力的想法就是枚举LCA,那就只需要考虑子树中的点对。有实际贡献意义的就...

Vectorxj的博客 622

[平等博弈][SG函数][字典树合并] BZOJ 4730: Alice和Bob又在玩游戏

SolutionSolutionSolution 记SuSuS_u为uuu到根的链的子树的SG函数值的集合。 考虑从子树转移到根。 一种是去掉根,就是把所有子树异或起来。 一种操作在子树内,相当于把子树的SSS异或上子树的SG异或和。 集合异或上一个数可以打标记。 集合的合并可以用字典树合并。 求mexmex\text{mex}可以二分。 #include &lt;bits/s...

Vectorxj的博客 602
上一篇: [容斥原理][DP] SRM 498 Div1 Hard FoxJumping
下一篇: [最长路][二分图]Codeforces 542 E. Playing on Graph
Vectorxj
博客等级 码龄11年 35粉丝 231原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值