• [SDOI2013]方程


    嘟嘟嘟


    这题思路还是非常显然的,烦人的就是模数不是质数。


    只考虑限制2,就是插板法,先强制让后面的未知数选那么多球。
    加上了限制1,因为(n1 leqslant 8),那直接(O(2 ^ 8))暴力容斥即可。
    细节就在于解必须是正整数,即每一个盒子至少放一个球,那么对于限制2,我们要强制先选(a _ i - 1)个球,而不是(a_i)个;同理限制1,容斥的时候至少超出限制的数得选(a_i)个球,而不是(a_i + 1)个。


    至此这道题已经全部搞完了。还剩下一个大问题:模数不是质数。
    把模数质因数分解,发现最大的质因数也很小,因此要用扩展lucas
    推荐一个很好的教程博客:【知识总结】扩展卢卡斯定理(exLucas)
    不过这个博客的代码效率不是很高,这道题会TLE两个点。然后我找了另一种写法,就是在求(n! \% p ^ k)的时候,我们可以先预处理前缀积(f[i](i < p ^ k)),满足如果(i | p),则(f[i] = f[i - 1]),否则(f[i] = f[i - 1] * i \% p ^ k)
    这样在递归的每一层,原先从1到(p ^ k)和从(1)(n \% p ^ k)分别扫一遍计算就改成(O(1))的了,快的飞起。

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<assert.h>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 20;
    In ll read()
    {
      ll ans = 0;
      char ch = getchar(), last = ' ';
      while(!isdigit(ch)) last = ch, ch = getchar();
      while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
      if(last == '-') ans = -ans;
      return ans;
    }
    In void write(ll x)
    {
      if(x < 0) x = -x, putchar('-');
      if(x >= 10) write(x / 10);
      putchar(x % 10 + '0');
    }
    In void MYFILE()
    {
    #ifndef mrclr
      freopen("ha.in", "r", stdin);
      freopen("ha.out", "w", stdout);
    #endif
    }
    
    ll n, n1, n2, m, mod, a[maxn];
    
    In ll inc(ll a, ll b, ll mod) {return a + b < mod ? a + b : a + b - mod;}
    In ll quickpow(ll a, ll b, ll mod)
    {
      ll ret = 1;
      for(; b; b >>= 1, a = a * a % mod)
        if(b & 1) ret = ret * a % mod;
      return ret;
    }
    In void exgcd(ll a, ll b, ll& x, ll& y)
    {
      if(!b) x = 1, y = 0;
      else exgcd(b, a % b, y, x), y -= a / b * x;
    }
    In ll inv(int a, ll p)
    {
      ll x, y;
      exgcd(a, p, x, y);
      return (x % p + p) % p;
    }
    
    const int maxN = 1e6 + 5;
    struct ExL
    {
      ll f[maxN];
      In ll Fac(ll n, ll p, ll pk)
      {
        if(n < p) return f[n];
        return quickpow(f[pk - 1], n / pk, pk) * f[n % pk] % pk * Fac(n / p, p, pk) % pk;
      }
      In ll C(ll n, ll m, ll p, ll pk)
      {
        if(m > n) return 0;
        f[0] = 1;
        for(int i = 1; i < pk; ++i)
          if(i % p) f[i] = f[i - 1] * i % pk;
          else f[i] = f[i - 1];
        ll f1 = Fac(n, p, pk), f2 = Fac(m, p, pk), f3 = Fac(n - m, p, pk), cnt = 0;
        for(ll i = n; i; i /= p) cnt += i / p;
        for(ll i = m; i; i /= p) cnt -= i / p;
        for(ll i = n - m; i; i /= p) cnt -= i / p;
        return f1 * inv(f2, pk) % pk * inv(f3, pk) % pk * quickpow(p, cnt, pk) % pk;
      }
      ll a[maxN], c[maxN], d[maxN], cnt;
      In ll CRT()
      {
        ll M = 1, ans = 0;
        for(int i = 1; i <= cnt; ++i) M *= c[i];
        for(int i = 1; i <= cnt; ++i)
          ans = inc(ans, a[i] * (M / c[i]) % M * inv(M / c[i], c[i]) % M, M);
        return ans;
      }
      In ll exlucas(ll n, ll m, ll p)
      {
        if(m > n) return 0;
        for(int i = 1; i <= cnt; ++i) a[i] = C(n, m, d[i], c[i]);
        return CRT();
      }
      In void init(ll mod)
      {
        if(mod == 10007)
          {
    	cnt = 1;
    	d[1] = c[1] = 10007;
          }
        if(mod == 262203414)
          {
    	cnt = 5;
    	d[1] = c[1] = 2, d[2] = c[2] = 3, d[3] = c[3] = 11;
    	d[4] = c[4] = 397, d[5] = c[5] = 10007;
          }
        if(mod == 437367875)
          {
    	cnt = 3;
    	d[1] = 5, d[2] = 7, d[3] = 101;
    	c[1] = 125, c[2] = 343, c[3] = 10201;
          }
      }
    }E;
    
    int main()
    {
      MYFILE();
      db Beg = clock();
      int T = read(); mod = read();
      E.init(mod);
      while(T--)
        {
          n = read(), n1 = read(), n2 = read(), m = read();
          for(int i = 1; i <= n1 + n2; ++i) a[i] = read();
          ll ans = 0, sum2 = 0;
          for(int i = n1 + 1; i <= n1 + n2; ++i) sum2 += a[i] - 1;
          for(int S = 0; S < (1 << n1); ++S)
    	{
    	  ll sum1 = 0, cnt = 0;
    	  for(int i = 1; i <= n1; ++i)
    	    if((S >> (i - 1)) & 1) sum1 += a[i], ++cnt;
    	  ll tp = E.exlucas(m - 1 - sum1 - sum2, n - 1, mod);
    	  ans = inc(ans, (cnt & 1) ? mod - tp : tp, mod);
    	}
          write(ans), enter;
        }
      db End = clock();
      //printf("%.3lf
    ", (End - Beg) / CLOCKS_PER_SEC);
      return 0;
    }
    
  • 相关阅读:
    android selector下的设置背景属性值
    成功必备的15种心态
    saveInstallState参数使用详解(android activity状态保存和恢复)
    14个坏习惯可能让你丢掉工作
    如何找到好书?有什么技巧或建议?
    [转]Git详解之一 Git起步
    程序员技术练级攻略
    Sina微博OAuth2框架解密
    程序员的八个级别
    Android中的Layout_weight详解
  • 原文地址:https://www.cnblogs.com/mrclr/p/10959670.html
Copyright © 2020-2023  润新知