• 集美大学校赛 B,C


    B - 小M的游戏

    思路:考虑最短路径上的博弈,对于sg(n),设定其为必败态,那么我们通过转移求出初始点为必败态还是必胜态即可。
    我们可以预处理出从 n 到任意点的最短路,对于点 u ,其后继节点能否被更新的条件为,两点之间的路径是否为最短路,然后运用sg函数去判断即可。

    #include 
    
    using namespace std;
    const int N = 2e5 + 5;
    typedef long long ll;
    typedef pair<ll, ll> pll;
    typedef array<ll, 3> p3;
    int mod = 1e9+7;
    const int maxv = 4e6 + 5;
    // #define endl "\n"
    
    vector<pll> e[N];
    
    void add(int u,int v,int w)
    {
        e[u].push_back({v,w});
        e[v].push_back({u,w});
    }
    int n,m;
    int f[N];
    ll d[N];
    bool st[N];
    
    void dijk()
    {
        d[n]=0;
        priority_queue<pll,vector<pll>,greater<pll> > q;
        q.push({d[n],n});
        while(!q.empty()){
            auto [dis,u]=q.top();
            q.pop();
            for(auto [v, w]: e[u]){
                if(d[v]>d[u]+w){
                    d[v]=d[u]+w;
                    q.push({d[v],v});
                }
            }
        }
    }
    
    int sg(int x)
    {
        if(f[x]!=-1) return f[x];
        ll res=d[x];
        set<int> s;
        for(auto [u,w]: e[x]){
            if(d[x]-d[u]==w) s.insert(sg(u));
        }
        for(int i=0;;i++){
            if(!s.count(i)){
                return f[x]=i;
            }
        }
    }
    
    
    void solve()
    {
    
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            e[i].clear();
            f[i]=-1;
            d[i]=2e18,st[i]=0;
        }
        for(int i=1;i<=m;i++){
            int u,v,w;
            cin>>u>>v>>w;
            add(u,v,w);
        }
        dijk();
        int t=sg(1);
    	if(t)cout << "Little M is the winner." << endl;
    	else cout << "Little I is the winner." << endl;
    }
    
    int main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);
        cout.tie(0);
        int t;
        t=1;
        cin>>t;
        while(t--){
            solve();
        }
        system("pause");
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    C - 方格染色

    思路:考虑组合数学,我们考虑将k个黑块分成 1 , 2 , 3 , 4...... k − 1 , k 1,2,3,4......k-1,k 1,2,3,4......k1,k块进行单独考虑,然后根据加法原理,将其相加即可。
    考虑当 k = i k=i k=i的情况:
    即现在一共有 n 个空,然后把 i 个球放入 n-( k - i ) 个空中,要求两两不相邻,一共有多少种方法。
    即运用隔板法,对于A个球,B个空,我们会空出B-A个空格,那么我们将其视为隔板,由此可以插入的位置为 B-A+1个,由此,将 A个球放入B个空的方法为 C B − A + 1 A C_{B-A+1}^{A} CBA+1A
    再次考虑,我们把k个块分成i块进行单独考虑,其拆分方式有多种,那么将其抽象为一般问题:
    即给定A个球,将其分给B个人(每个人最少获得一个),有多少种分法。
    我们将A个球看作一个序列,将其分为B个人,我们将其看作把这个序列分成几段,所以我们想要将其分成B段的话,我们需要切B-1刀,而我们能进行切割的地方为A-1个,所以综上所述,答案为 C A − 1 B − 1 C_{A-1}^{B-1} CA1B1
    再次考虑,分成i块,我们单独看每一块,其内部有两种排序方法。
    综上所述,根据乘法原理,我们将其相乘即可。

    #include 
    
    using namespace std;
    const int N = 2e5 + 5;
    typedef long long ll;
    typedef pair<ll, ll> pll;
    typedef array<ll, 3> p3;
    int mod = 1e9+7;
    const int maxv = 4e6 + 5;
    // #define endl "\n"
    
    template<const int T>
    struct ModInt {
        const static int mod = T;
        int x;
        ModInt(int x = 0) : x(x % mod) {}
        ModInt(long long x) : x(int(x % mod)) {} 
        int val() { return x; }
        ModInt operator + (const ModInt &a) const { int x0 = x + a.x; return ModInt(x0 < mod ? x0 : x0 - mod); }
        ModInt operator - (const ModInt &a) const { int x0 = x - a.x; return ModInt(x0 < 0 ? x0 + mod : x0); }
        ModInt operator * (const ModInt &a) const { return ModInt(1LL * x * a.x % mod); }
        ModInt operator / (const ModInt &a) const { return *this * a.inv(); }
        bool operator == (const ModInt &a) const { return x == a.x; };
        bool operator != (const ModInt &a) const { return x != a.x; };
        void operator += (const ModInt &a) { x += a.x; if (x >= mod) x -= mod; }
        void operator -= (const ModInt &a) { x -= a.x; if (x < 0) x += mod; }
        void operator *= (const ModInt &a) { x = 1LL * x * a.x % mod; }
        void operator /= (const ModInt &a) { *this = *this / a; }
        friend ModInt operator + (int y, const ModInt &a){ int x0 = y + a.x; return ModInt(x0 < mod ? x0 : x0 - mod); }
        friend ModInt operator - (int y, const ModInt &a){ int x0 = y - a.x; return ModInt(x0 < 0 ? x0 + mod : x0); }
        friend ModInt operator * (int y, const ModInt &a){ return ModInt(1LL * y * a.x % mod);}
        friend ModInt operator / (int y, const ModInt &a){ return ModInt(y) / a;}
        friend ostream &operator<<(ostream &os, const ModInt &a) { return os << a.x;}
        friend istream &operator>>(istream &is, ModInt &t){return is >> t.x;}
    
        ModInt pow(int64_t n) const {
            ModInt res(1), mul(x);
            while(n){
                if (n & 1) res *= mul;
                mul *= mul;
                n >>= 1;
            }
            return res;
        }
        
        ModInt inv() const {
            int a = x, b = mod, u = 1, v = 0;
            while (b) {
                int t = a / b;
                a -= t * b; swap(a, b);
                u -= t * v; swap(u, v);
            }
            if (u < 0) u += mod;
            return u;
        }
        
    };
    using mint = ModInt<998244353>;
    // constexpr mod = ...;
    // using Mint = modint;
    struct Fact {
        vector<mint> fact, factinv,er;
        const int n;
        Fact(const int& _n) : n(_n), fact(_n + 1, mint(1)), factinv(_n + 1),er(_n+1,mint(1)) {
            for (int i = 1; i <= n; ++i) fact[i] = fact[i - 1] * i;
            for (int i = 1; i <= n; i++) er[i]=er[i-1]*2;
            factinv[n] = fact[n].inv();
            for (int i = n; i; --i) factinv[i - 1] = factinv[i] * i;
        }
        mint C(const int& n, const int& k) {
            if (n < 0 || k < 0 || n < k) return 0;
            return fact[n] * factinv[k] * factinv[n - k];
        }
        mint A(const int& n, const int& k) {
            if (n < 0 || k < 0 || n < k) return 0;
            return fact[n] * factinv[n - k];
        }
        mint E(const int& n){
            return er[n];
        }
    };
    
    Fact z(N-2);
    void solve()
    {
        int n,k;
        cin>>n>>k;
    	if(k == 0)
    	{
    		cout << 1 << endl;
    		return;
    	}
        mint ans=0;
        int d=n-k+1;
        for(int i=1;i<=k;i++){
            mint t1=z.C(d,i)*z.C(k-1,i-1)*z.E(i);
            ans+=t1;
        }
        cout<<ans<<endl;
    
    }
    
    int main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);
        cout.tie(0);
        int t;
        t=1;
        cin>>t;
        while(t--){
            solve();
        }
        system("pause");
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
  • 相关阅读:
    Avue树结构懒加载子节点不刷新
    【Spring容器的启动过程】
    华测监测预警系统 2.2 任意文件读取漏洞复现 [附POC]
    SpringBoot 整合Thymeleaf教程及使用
    主从延迟&读写不一致解决方案分析
    win11-qt5.14配置
    一组完整的读Json配置信息的辅助函数
    js获取当前月份天数,获取指定月份的天数
    TCP/IP协议专栏——ARP攻击原理与分类——网络入门和工程维护必看
    C/C++教程 从入门到精通《第二十六章》——Linux开发服务器详解
  • 原文地址:https://blog.csdn.net/Unlimited_ci/article/details/134408827