Atcoder grand 025 组合数学塔涂色 贪心走路博弈

A

B

题意:给你N个数(3e5) 每个数可以是0,a,b,a+b(3e5) 但是总数加起来要是定值K(18e10)

问总方法数mod 998244353

解:

把a+b的看成是一个a加上一个b的 这样从0-N枚举a的个数 判断b的个数是否合法

如果合法的话 这种情况的所有方法数就相当于在N个中选i个放a 然后再在N个中选剩下的b个放b

anser = (anser + (ncr(n, i) * ncr(n, remain / B) % mod)) % mod

/*Huyyt*/
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int dir[8][2] = {{0, 1}, {1, 0}, {0, -1}, { -1, 0}, {1, 1}, {1, -1}, { -1, -1}, { -1, 1}};
const int mod = 998244353, gakki = 5 + 2 + 1 + 19880611 + 1e9;
const int MAXN = 2e5 + 5, MAXM = 2e5 + 5, N = 3e5 + 5;
int to[MAXM << 1], nxt[MAXM << 1], Head[MAXN], tot = 1;
inline void addedge(int u, int v)
{
        to[++tot] = v;
        nxt[tot] = Head[u];
        Head[u] = tot;
}
ll Qpow(ll a, ll b)
{
        ll ans = 1, base = a;
        while (b != 0)
        {
                if (b & 1 != 0)
                {
                        ans = (ans * base) % mod;
                }
                base = (base * base) % mod;
                b >>= 1LL;
        }
        return ans % mod;
}
ll Inv(ll a)
{
        return Qpow(a, mod - 2);
}
ll fact[N], Invfact[N], anser = 0;
ll ncr(ll n, ll r)
{
        if (r < 0 || n < 0)
        {
                return 0;
        }
        if (n < r)
        {
                return 0;
        }
        ll a = fact[n];
        a = (a * Invfact[r]) % mod;
        a = (a * Invfact[n - r]) % mod;
        return a;
}
int main()
{
        ios_base::sync_with_stdio(0);
        cin.tie(0);
        ll n, A, B, K;
        cin >> n >> A >> B >> K;
        Invfact[0] = Invfact[1] = fact[0] = fact[1] = 1;
        for (ll i = 2; i <= 3e5 + 1; i++)
        {
                fact[i] = (fact[i - 1] * i) % mod;
                Invfact[i] = Inv(fact[i]);
        }
        ll remain;
        for (ll i = 0; i <= n; i++)
        {
                remain = K - i * A;
                if (remain >= 0 && remain % B == 0 && remain / B <= n)
                {
                        anser = (anser + (ncr(n, i) * ncr(n, remain / B) % mod)) % mod;
                }
        }
        cout << anser << endl;
        return 0;
}
View Code

C

题意:给你一个数轴和N个线段 有两个人A,B A每次给B一个线段 要求B要走到线段的范围内 B初始在原点

A会选最优方案使得B走的距离最远 而B会选最优方案使得自己走的距离最少 问你最后B走的距离是多少

解:

A选的方案肯定是使得B在原点左右来回跑 这样使得跑的距离最大

这样我们把L从大到小排列 把R从小到大排列 如果有L>R 就说明B需要走这么长的距离来满足条件

/*Huyyt*/
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int dir[8][2] = {{0, 1}, {1, 0}, {0, -1}, { -1, 0}, {1, 1}, {1, -1}, { -1, -1}, { -1, 1}};
const int mod = 998244353, gakki = 5 + 2 + 1 + 19880611 + 1e9;
const int MAXN = 2e5 + 5, MAXM = 2e5 + 5, N = 1e5 + 5;
int to[MAXM << 1], nxt[MAXM << 1], Head[MAXN], tot = 1;
inline void addedge(int u, int v)
{
        to[++tot] = v;
        nxt[tot] = Head[u];
        Head[u] = tot;
}
vector<int> l, r;
int main()
{
        ios_base::sync_with_stdio(0);
        cin.tie(0);
        int n;
        cin >> n;
        l.push_back(0), r.push_back(0);
        for (int i = 1; i <= n; i++)
        {
                int L, R;
                cin >> L >> R;
                l.push_back(L);
                r.push_back(R);
        }
        ll anser = 0;
        sort(l.rbegin(), l.rend());
        sort(r.begin(), r.end());
        for (int i = 0; i <= n; i++)
        {
                if (l[i] > r[i])
                {
                        anser += 2LL * (l[i] - r[i]);
                }
        }
        cout << anser << endl;
        return 0;
}
View Code

 

posted @ 2018-06-04 22:04  Aragaki  阅读(234)  评论(0编辑  收藏  举报