zoukankan      html  css  js  c++  java
  • AtCoder Beginner Contest 172 部分题解

    C:给两个栈,每次只能取栈顶元素,取完后自动pop  问能取到最多几个元素

    栈中元素之和必须小于等于K


    官方题解给出的做法是O(N+M) 受上一场CF启发,此题可以很自然联想到二分做法。  二分答案,答案显然具有单调性。check函数只需遍历一遍可能情况

    复杂度O((N+M)logX) 

    int n, m;
    ll k;
    ll a[maxn], b[maxn];
    ll sum1[maxn];
    ll sum2[maxn];
    
    bool check(int x) {
        for (int i = x - m ; i <= min(x,n); i++) {
            if (sum1[i] + sum2[x - i] <= k) {
                //cout << x << " " << i <<" "<< x - i << endl;
                return 1;
            }
        }
        return 0;
    }
    
    int main() {
        scanf("%d%d%lld", &n, &m, &k);
        for (int i = 1; i <= n; i++) {
            scanf("%lld", a + i );  sum1[i] = sum1[i - 1] + a[i];
        }
        for (int i = 1; i <= m; i++) {
            scanf("%lld", b + i); sum2[i] = sum2[i - 1] + b[i];
        }
        int l = 0, r = n + m;
        while (l < r) {
            int mid = l + r + 1 >> 1;
            if (check(mid)) l = mid;
            else r = mid - 1;
        }
        if (check(l)) printf("%d", l);
        else printf("%d", l-1);
    }
    View Code

    D:

    函数F(x) 表示x的因子个数 。 求 sgma i*F(i)          N<=1e7

    利用d(i)==(每个质因数的指数+1)的积 跑一遍素数筛顺便可筛出F函数,之后相乘即可

    int n;
    ll d[maxn], minn[maxn], prime[maxn];
    bool is[maxn];
    int tot;
    
    void init() {
        d[1] = 1;
        for (int i = 2; i <= n; i++)
        {
            if (is[i] == 0) prime[++tot] = i, d[i] = 2, minn[i] = 1;
            for (re int j = 1; prime[j] * i <= n && j <= tot; j++)
            {
                is[i * prime[j]] = 1;
                if (i % prime[j] == 0)
                {
                    minn[i * prime[j]] = minn[i] + 1;
                    d[i * prime[j]] = d[i] / (minn[i] + 1) * (minn[prime[j] * i] + 1);
                    break;
                }
                minn[i * prime[j]] = 1;
                d[i * prime[j]] = d[i] * 2;
            }
        }
    }
    
    int main() {
        scanf("%d", &n);
        init();
        ll res = 0;
        for (int i = 1; i <= n; i++) {
            res += i * d[i];
        }
        printf("%lld", res);
    }
    View Code

    E:

    构造一对数组a,b  要求满足 数组中数字均不超过M。 且 1.a中元素互不相同 2.b中元素互不相同 3.ai不等于bi  问可构造出多少对

    1<=N<=M<=5e5

    推公式即可  先把a数组定下来,有A(n,m) 种选法。 再考虑所有情况减去不对的情况。 故容斥(实际上是错排的推广) 

    注意最后不对的情况要除以(m-n)!去重

    注意取逆元。

    ll inv[maxn];
    ll n, m;
    
    void inver(ll p) {
        inv[0] = 1;
        inv[1] = 1;
        for (int i = 2; i <= m; i++) {
            inv[i] = (p - p / i) * inv[p % i] % p;
        }
    }
    
    
    ll c[maxn];
    ll fac[maxn];
    
    ll quickPower(ll a, ll b, ll m) {   //计算a的b次方
        ll ans = 1;
        ll base = a;
        while (b) {
            if (b & 1) {
                ans *= base;
                ans %= m;
            }
            base *= base;
            base %= m;
            b >>= 1;   //注意是b>>=1 not b>>1
        }
        return ans;
    }
    
    ll get_inv(ll x) {
        return quickPower(x, MOD - 2, MOD);
    }
    
    void get_fac() {
        fac[0] = 1;
        for (int i = 1; i <= m; i++) {
            fac[i] = (fac[i - 1] * i)%MOD;
        }
    }
    
    void get_C(ll n) {
        c[0] = 1;
        for (int i = 0; i < n; i++) c[i + 1] = ((c[i] * (n - i)) % MOD * inv[i + 1]) % MOD;
    }
    
    int main() {
        scanf("%lld%lld", &n, &m);
        inver(MOD);
        get_fac();
        get_C(n);
        ll res = (1 * ((fac[m] * get_inv(fac[m - n])) % MOD * get_inv(fac[m - n])) % MOD)%MOD;
        ll tmp = fac[m];
        int f = 1;
        for (int i = 1; i <= n; i++) {
            tmp = (tmp + ((-1ll * f) * ((c[i] * fac[m - i]) % MOD))+MOD) % MOD;
            f *= -1;
        }
        //cout << res << tmp << endl;
        printf("%lld", (tmp * res) % MOD);
    }
    View Code

    F:

    NIm博弈  不同之处在于 后手者可以在游戏开始前取出第一堆中的若干个放到第二堆中 问最少放几个可以保证他必胜 若不能输出-1

    2<=N<=300     1<=ai<=1e12

    ll a[305];
    ll m, s;
    
    int main() {
        int n;
        scanf("%d", &n);
        for (int i = 0; i < n; i++) scanf("%lld", a + i);
        m = a[2];
        for (int i = 3; i < n; i++) m ^= a[i];
        s = a[0] + a[1];
        ll rem = s - m;
        if ((rem % 2) || (rem < 0)) {
            puts("-1");
            return 0;
        }
        rem /= 2;
        ll b = rem;
        int f = 1;
        for (ll i = 50; i >= 0; i--) {
            ll p = 1ll << i;
            if ((m & p) && (rem & p)) f = 0;
            if ((m & p) && ((b + p) <= a[0])) b += p;
        }
        b = a[0] - b;
        if ((b >= a[0]) || (b < 0)) f = 0;
        if (f) printf("%lld", b);
        else puts("-1");
    }
    View Code
  • 相关阅读:
    cout输出字符串指针
    《深度探索c++对象模型》chapter2 构造函数语义学
    c++virtual inline 是否冲突
    《深度探索c++对象模型》chapter1关于对象对象模型
    《More Effective C++》 条款5 谨慎定义类型转换函数
    《Effective C++》条款26 防卫潜伏的ambiguity模棱两可的状态
    《Effective C++》条款14 总是让base class拥有virtual destructor
    《Effective C++》内存管理
    c++类型转换Type Cast)
    C++中的new/delete与operator new/operator delete
  • 原文地址:https://www.cnblogs.com/hznumqf/p/13202689.html
Copyright © 2011-2022 走看看