• CF1594


    D - The Number of Imposters(2-sat)

    每个人分成T,F两种结点,分别代表这人是诚实的还是不诚实的。然后连边,例如(a)(b)是T,那么就有如果(a)是T推出(b)是T,于是连一条双向边:(aT Leftrightarrow bT),以此类推。然后直接dfs跑,最后判一下有没有矛盾。

    #include <bits/stdc++.h>
    
    #define endl '
    '
    #define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
    #define mp make_pair
    #define seteps(N) fixed << setprecision(N) 
    typedef long long ll;
    
    using namespace std;
    /*-----------------------------------------------------------------*/
    
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    #define INF 0x3f3f3f3f
    
    const int N = 1e6 + 10;
    const double eps = 1e-5;
    
    bool vis[N];
    bool visid[N];
    vector<int> np[N];
    
    int get(int p, int st) { // 1 T 0 F
        if(st) return 2 * p - 1;
        return 2 * p;
    }
    
    void add(int u, int v) {
        np[u].push_back(v);
        np[v].push_back(u);
    }
    int cnt, fcnt;
    void dfs(int p) {
        cnt++;
        fcnt += (p % 2 == 0);
        visid[(p + 1) / 2] = 1;
        vis[p] = 1;
        for(int nt : np[p]) {
            if(vis[nt]) continue;
            dfs(nt);
        }
    }
    
    int main() {
        IOS;
        int t;
        cin >> t;
        while(t--) {
            int n, m;
            cin >> n >> m;
            for(int i = 1; i <= 2 * n; i++) {
                vis[i] = 0;
                visid[i] = 0;
                np[i].clear();
            }
            while(m--) {
                int a, b;
                string c;
                cin >> a >> b >> c;
                bool flag = (c == "crewmate");
                add(get(a, 1), get(b, flag));
                add(get(a, 0), get(b, !flag));
            }
            int ans = 0;
            for(int i = 1; i <= 2 * n; i++) {
                if(visid[(i + 1) / 2]) continue;
                cnt = fcnt = 0;
                dfs(i);
                ans += max(cnt - fcnt, fcnt);
            }
            bool ok = true;
            for(int i = 1; i <= n; i++) {
                if(vis[get(i, 1)] && vis[get(i, 0)]) {
                    ok = false;
                    break;
                }
            }
            if(ok) cout << ans << endl;
            else cout << -1 << endl;
        }
    }
    

    E - Rubik's Cube Coloring (hard version) - (树上dp)

    染色的结点只会影响从它到根结点的路径上的点,将所有染色结点以及它们到根结点的路径全部提出来,可以得到一颗树,点数最多为(60 imes 2000)。剩余的点显然都是只有4种染色方式,然后处理树上的染色方案数。直接树上dp,设(dp[p][c])代表结点(p)染色(c)时方案数。有转移方程

    [dp[p][c]=sum{dp[u][c_1] cdot dp[v][c_2]} ]

    (u,v)(p)的儿子,(c_1,c_2)是和(c)合法的颜色。

    注意写前搞清楚dp转移方程,在纸上写下来。不要搞错了。

    #include <bits/stdc++.h>
    
    #define endl '
    '
    #define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
    #define mp make_pair
    #define seteps(N) fixed << setprecision(N) 
    typedef long long ll;
    
    using namespace std;
    /*-----------------------------------------------------------------*/
    
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    #define INF 0x3f3f3f3f
    
    const int N = 3e5 + 10;
    const int M = 1e9 + 7;
    const double eps = 1e-5;
    typedef pair<int, int> PII;
    map<string, int > id;
    vector<ll> cn[N];
    vector<ll> num;
    vector<int> np[N];
    int qcol[N];
    int col[N];
    ll dp[N][10];
    bool vis[N];
    
    inline ll qpow(ll a, ll b, ll m) {
        ll res = 1;
        while(b) {
            if(b & 1) res = (res * a) % m;
            a = (a * a) % m;
            b = b >> 1;
        }
        return res;
    }
    
    int getid(ll x) {
        return lower_bound(num.begin(), num.end(), x) - num.begin() + 1;
    }
    
    void cal(int p, int fa, int c) {
        vector<int> son;
        for(int nt : np[p]) {
            if(nt == fa) continue;
            son.push_back(nt);
        }
        if(son.size() == 0) {
            dp[p][c] = 1;
        } else if(son.size() == 1) {
            int u = son.front();
            for(int i = 2; i <= 7; i++) {
                if(c == i || c == (i ^ 1)) continue;
                dp[p][c] += dp[u][i];
                dp[p][c] %= M;
            }
        } else {
            int u = son.front(), v = son.back();
            for(int i = 2; i <= 7; i++) {
                for(int j = 2; j <= 7; j++) {
                    if(c == i || c == (i ^ 1)) continue;
                    if(c == j || c == (j ^ 1)) continue;
                    dp[p][c] += dp[u][i] * dp[v][j] % M;
                    dp[p][c] %= M;
                }
            }
        }
    }
    
    void dfs(int p, int fa) {
        for(int nt : np[p]) {
            if(nt == fa) continue;
            dfs(nt, p);
        }
        if(col[p]) {
            cal(p, fa, col[p]);
        } else {
            for(int i = 2; i <= 7; i++) {
                cal(p, fa, i);
            }
        }
    }
    
    int main() {
        IOS;
        id["white"] = 2;
        id["yellow"] = 3;
        id["green"] = 4;
        id["blue"] = 5;
        id["red"] = 6;
        id["orange"] = 7;
        int k, n;
        cin >> k >> n;
        for(int i = 1; i <= n; i++) {
            ll v;
            string c;
            cin >> v >> c;
            while(v) {
                num.push_back(v);
                cn[i].push_back(v);
                v >>= 1;
            }
            qcol[i] = id[c];
        }
        sort(num.begin(), num.end());
        num.erase(unique(num.begin(), num.end()), num.end());
        for(int i = 1; i <= n; i++) {
            int u = getid(cn[i].front());
            col[u] = qcol[i];
            for(int j = 1; j < cn[i].size(); j++) {
                int v = getid(cn[i][j]);
                np[u].push_back(v);
                np[v].push_back(u);
                u = v;
            }
        }
        for(int i = 1; i <= num.size(); i++) {
            sort(np[i].begin(), np[i].end());
            np[i].erase(unique(np[i].begin(), np[i].end()), np[i].end());
        }
        dfs(1, 0);
        ll ans = 1;
        ll ret = ((1ll << k) - 1) - num.size();
        ll res = 0;
        for(int i = 2; i <= 7; i++) res = (res + dp[1][i]) % M;
        ans =  qpow(4, ret % (M - 1), M) * res % M;
        cout << ans << endl;
    }
    

    F - Ideal Farm (思维,构造)

    如果(s < k),答案是NO ;(s=k)答案是YES

    (s>k)时,设分配为(a_1,...a_n),有分配的前缀和为(p_1,...,p_n),其中(p_n = s)(p_i < p_{i+1})(p_1 ge 1)

    这样转化后就比较好处理,假设存在某个(p_i),有(p_i +k=p_j),那么说明存在一个区间和为(k)。因此再创建一个数组(b),有(b_i=p_i+k)(b_0=k)。这样就有包含(n)个元素的(p)和包含(n+1)个元素的数组(b),一共(2n+1)个元素。

    显然,答案为NO的充要条件就是存在一个分配,使得(p)中任意一个元素都不等于(b)中任意一个元素,等价于(p)(b)构成一个新数组(pb)后里面的元素各不相同。显然这(2n+1)个元素的值域为([1,s+k])。如果能找到(pb)的最长分配使得前面的条件成立,设最长的分配长度为(m),那么有(2n+1le m)答案为NO,否则答案为YES。因为一旦有最长的分配使得条件成立,让条件成立的更短的分配一定可以从中构造出来。

    注意(p)的值域为([1,s])(b)的值域为([k,s+k])。最优(长)的分配方案就是(k)个一组,一组一组分别分配给(p)(b)。例如([2k,3k-1])分配给(p)([3k,4k-1])分配给(b),这样即满足各不相同又满足了(b_i=p_i+k)。可以发现,这样是成对分配的,所以要看(lfloor frac{s}{k} floor)是奇数还是偶数,如果是奇数,最后还会剩下一组。最后剩下的从小到大分配即可。注意,([s+1,s+k])这部分的值只能分配给(b)。画一下图很好理解。这样就能得到最长的分配长度。

    #include <bits/stdc++.h>
    
    #define endl '
    '
    #define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
    #define mp make_pair
    #define seteps(N) fixed << setprecision(N) 
    typedef long long ll;
    
    using namespace std;
    /*-----------------------------------------------------------------*/
    
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    #define INF 0x3f3f3f3f
    
    const int N = 3e5 + 10;
    const double eps = 1e-5;
    
    
    int main() {
        IOS;
        int t;
        cin >> t;
        while(t--) {
            ll s, n, k;
            cin >> s >> n >> k;
            if(s < k) cout << "NO" << endl;
            else if(s == k) cout << "YES" << endl;
            else {
                ll b = s % k + 1;
                ll a = k - b;
                ll m;
                if((s / k) % 2 == 1) {
                    m = s + k - b;
                } else {
                    m = s + k - a;
                }
                if(2 * n + 1 <= m) {
                    cout << "NO" << endl;
                } else 
                    cout << "YES" << endl;
            }
        }
    }
    
  • 相关阅读:
    (转)ASP.NET Mvc 2.0 1. Areas的创建与执行
    新世代交易管理機制~System.Transactions
    水晶報表入門
    MyGeneration 如何连接 mysql 来生成代码
    vs.net 启动不了
    Oracle面试问题-技术篇
    把excel两列字符数据用逗号合并起来
    论Leader的技能
    物流行业名词
    html 向aspx 页面传值
  • 原文地址:https://www.cnblogs.com/limil/p/15387014.html
Copyright © 2020-2023  润新知