【每日一题】二分图染色

二分图染色(弱化版)

http://www.nowcoder.com/questionTerminal/b091d1cd01f941acb6337c8d8d318404

根据楚巨的描述,这个题目有亿点点难……

题目传送

图片说明

Solution

根据二分图的解题套路,可以转换为一个n * n的矩阵中去进行处理,又因为题目给了边的特性,我们假设xi,yi填上红色就是xi,yi的边涂成红色(因为绿色的没啥特性,所以可以不管这种颜色),两红边(蓝边类似)不能共享端点,也就是说在n * n的矩阵中,任意的一行或一列不能有相同颜色的点。
1、只填红色或者蓝色,显然有f[n] = 图片说明 种方案。(n行里面取若干行,没有次序之分,再取若干列,这时候2 1和1 2,存在差别,所以要使用全排列)。
2、红蓝都有,我们枚举红蓝重复的边数x,根据容斥的思想那么答案就是图片说明 ,最终求和得到答案等于图片说明

3、分析时间复杂度的时候发现预处理阶乘和逆元都可以通过O(n)搞定,不过按照我们上面的组合数×全排列的
方法时间复杂度是O(图片说明 ),n是1e7,TLE妥妥的。那我们怎么办呢? 欸嘿嘿打表图片说明 2,7,34,209,1546,13327,130922……再根据一个神奇的网站OEIS,一找,果然有递推关系。
f[x]=2 * x * f[x-1]-f[x-2] * 图片说明

注意存在减法!!取模需谨慎,还有阶乘,ll开起来,(虽然我没开 =_= ).

Code

#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
typedef long long ll;

inline int read() {
    int s = 0, w = 1; char ch = getchar();
    while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); }
    while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    return s * w;
}

const int N = 1e7 + 5;
const int MOD = 1e9 + 7;
int jc[N], inv[N], f[N];

ll qpow(ll a, ll b) {
    ll ans = 1;
    while (b) {
        if (b & 1)    ans = ans * a % MOD;
        b >>= 1;
        a = a * a % MOD;
    }
    return ans;
}

void init(int n) { //预处理阶乘数组和逆元,求解组合数
    jc[0] = 1;
    for (int i = 1; i <= n; ++i)
        jc[i] = 1ll * jc[i - 1] * i % MOD;
    inv[n] = qpow(jc[n], MOD - 2);
    for (int i = n - 1; i >= 0; --i)
        inv[i] = 1ll * inv[i + 1] * (i + 1) % MOD;
    f[0] = 1; f[1] = 2; //线性递推f数组
    for (int i = 2; i <= n; ++i) {
        f[i] = (2ll * i * f[i - 1] - 1ll * f[i - 2] * (i - 1) % MOD * (i - 1) % MOD) % MOD;
        (f[i] += MOD) %= MOD; //保证正数
    }
}

ll C(int n, int m) {
    return 1ll * jc[n] * inv[m] % MOD * inv[n - m] % MOD;
}

ll A(int n, int m) {
    return 1ll * jc[n] * inv[n - m] % MOD;
}

int main() {
    int n = read();
    init(n);
    ll ans = 0;
    for (int i = 0; i <= n; ++i) {
        ll k = 1;
        if (i & 1) k = -1;
        ans += k * C(n, i) * A(n, i) % MOD * f[n - i] % MOD * f[n - i] % MOD;
        ans %= MOD;
    }
    printf("%lld\n", (ans + MOD) % MOD);
    return 0;
}
每日一题 文章被收录于专栏

每日一题

全部评论

相关推荐

不愿透露姓名的神秘牛友
03-15 10:59
已编辑
爱写代码的菜code...:哎,自己当时拿到字节offer的时候也在感叹终于拿到了,自己当时最想去的企业就是字节,结果还是阴差阳错去了鹅厂。祝uu一切顺利!!!
点赞 评论 收藏
分享
自从我室友在计算机导论课上听说了“刷&nbsp;LeetCode&nbsp;是进入大厂的敲门砖”,整个人就跟走火入魔了一样。他在宿舍门口贴了一张A4纸,上面写着:“正在&nbsp;DP,请勿打扰,否则&nbsp;Time&nbsp;Limit&nbsp;Exceeded。”日记本的扉页被他用黑色水笔加粗描了三遍:“Talk&nbsp;is&nbsp;cheap.&nbsp;Show&nbsp;me&nbsp;the&nbsp;code。”连宿舍聚餐,他都要给我们讲解:“今天的座位安排可以用回溯算法解决,但为了避免栈溢出,我建议用动态规划。来,这是状态转移方程:dp[i][j]&nbsp;代表第&nbsp;i&nbsp;个人坐在第&nbsp;j&nbsp;个位置的最优解。”我让他去楼下取个快递,他不直接去,非要在门口踱步,嘴里念念有词:“这是一个图的遍历问题。从宿舍楼(root)到驿站(target&nbsp;node),我应该用&nbsp;BFS&nbsp;还是&nbsp;DFS?嗯,求最短路径,还是广度优先好。”和同学约好出去开黑,他会提前发消息:“集合点&nbsp;(x,&nbsp;y),我们俩的路径有&nbsp;k&nbsp;个交点,为了最小化时间复杂度,应该在&nbsp;(x/2,&nbsp;y/2)&nbsp;处汇合。”有一次另一个室友低血糖犯了,让他帮忙找颗糖,他居然冷静地分析道:“别急,这是一个查找问题。零食箱是无序数组,暴力查找是&nbsp;O(n)。如果按甜度排序,我就可以用二分查找,时间复杂度降到&nbsp;O(log&nbsp;n)。”他做卫生也要讲究算法效率:“拖地是典型的岛屿问题,要先把连通的污渍区块都清理掉。倒垃圾可以用双指针法,一个指针从左往右,一个从右往左,能最快匹配垃圾分类。”现在我们宿舍的画风已经完全变了,大家不聊游戏和妹子,对话都是这样的:“你&nbsp;Two&nbsp;Sum&nbsp;刷了几遍了?”“别提了,昨天遇到一道&nbsp;Hard&nbsp;题,我连暴力解都想不出来,最后只能看题解。你呢?”“我动态规划还不行,总是找不到最优子结构。今天那道接雨水给我整麻了。”……LeetCode&nbsp;真的害了我室友!!!
老六f:编程嘉豪来了
AI时代还有必要刷lee...
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务