zoukankan      html  css  js  c++  java
  • 2021.5.11GRYZ模拟赛-数论专题

    写在前面

    啊啊啊啊 T3 结论假了假了假了假了假了。。。

    我脑子过期了,弃了。。

    所有题目详情可点击这里查看。

    得分情况

    题号 期望得分 实际得分
    (T1) 100 100
    (T2) 30 0
    (T3) 100 0
    230 100

    T1

    一道类似的题目:P1009 [NOIP1998 普及组] 阶乘之和

    考场思路

    直接计算阶乘值,然后加和输出结果。

    注意到数据范围过大,应用高精度加法和乘法。

    #include <cstdio>
    #include <iostream>
    #include <vector>
    #include <iomanip>
    #include <cassert>
    #include <algorithm>
    #include <cstring>
    typedef long long LL;
    using namespace std;
    
    //*=========================================快读*/
    inline LL read()
    {
    	LL s = 1, w = 0;
    	char ch = getchar();
    	for (; !isdigit(ch); ch = getchar())
    		if (ch == '-')
    			s = -1;
    	for (; isdigit(ch); ch = getchar())
    		w = w * 10 + ch - '0';
    	return s * w;
    }
    //*=====================================定义变量*/
    const int MARX = 1010;
    const int Big_B = 10;
    const int Big_L = 1;
    
    inline int intcmp_(int a, int b)
    {
    	if (a > b)
    		return 1;
    	return a < b ? -1 : 0;
    }
    
    struct Int
    {
    #define rg register
    
    	vector<int> c;
    
    	inline int max(int a, int b)
    	{
    		return a > b ? a : b;
    	}
    	inline int min(int a, int b)
    	{
    		return a < b ? a : b;
    	}
    
    	Int() {}
    	Int(int x)
    	{
    		for (; x > 0; c.push_back(x % Big_B), x /= Big_B)
    			;
    	}
    	Int(LL x)
    	{
    		for (; x > 0; c.push_back(x % Big_B), x /= Big_B)
    			;
    	}
    
    	inline void CrZ()
    	{
    		for (; !c.empty() && c.back() == 0; c.pop_back())
    			;
    	}
    
    	inline Int &operator+=(const Int &rhs)
    	{
    		c.resize(max(c.size(), rhs.c.size()));
    		rg int i, t = 0, S;
    		for (i = 0, S = rhs.c.size(); i < S; ++i)
    			c[i] += rhs.c[i] + t, t = c[i] >= Big_B, c[i] -= Big_B & (-t);
    		for (i = rhs.c.size(), S = c.size(); t && i < S; ++i)
    			c[i] += t, t = c[i] >= Big_B, c[i] -= Big_B & (-t);
    		if (t)
    			c.push_back(t);
    		return *this;
    	}
    
    	inline Int &operator-=(const Int &rhs)
    	{
    		c.resize(max(c.size(), rhs.c.size()));
    		rg int i, t = 0, S;
    		for (i = 0, S = rhs.c.size(); i < S; ++i)
    			c[i] -= rhs.c[i] + t, t = c[i] < 0, c[i] += Big_B & (-t);
    		for (i = rhs.c.size(), S = c.size(); t && i < S; ++i)
    			c[i] -= t, t = c[i] < 0, c[i] += Big_B & (-t);
    		CrZ();
    		return *this;
    	}
    
    	inline Int &operator*=(const Int &rhs)
    	{
    		rg int na = c.size(), i, j, S, ai;
    		c.resize(na + rhs.c.size());
    		LL t;
    		for (i = na - 1; i >= 0; --i)
    		{
    			ai = c[i], t = 0, c[i] = 0;
    			for (j = 0, S = rhs.c.size(); j < S; ++j)
    			{
    				t += c[i + j] + (LL)ai * rhs.c[j];
    				c[i + j] = t % Big_B, t /= Big_B;
    			}
    			for (j = rhs.c.size(), S = c.size(); t != 0 && i + j < S; ++j)
    				t += c[i + j], c[i + j] = t % Big_B, t /= Big_B;
    			assert(t == 0);
    		}
    		CrZ();
    		return *this;
    	}
    
    	inline Int &shlb(int l = 1)
    	{
    		if (c.empty())
    			return *this;
    		c.resize(c.size() + l);
    		rg int i;
    		for (i = c.size() - 1; i >= l; --i)
    			c[i] = c[i - l];
    		for (i = 0; i < l; ++i)
    			c[i] = 0;
    		return *this;
    	}
    
    	inline Int &shrb(int l = 1)
    	{
    		for (rg int i = 0; i < c.size() - l; ++i)
    			c[i] = c[i + l];
    		c.resize(max(c.size() - l, 0));
    		return *this;
    	}
    
    	inline Int div(const Int &rhs)
    	{
    		assert(!rhs.c.empty());
    		Int q, r;
    		rg int i;
    		if (rhs > *this)
    			return 0;
    		q.c.resize(c.size() - rhs.c.size() + 1);
    		rg int _l, _r, mid;
    		for (i = c.size() - 1; i > c.size() - rhs.c.size(); --i)
    			r.shlb(), r += c[i];
    		for (i = c.size() - rhs.c.size(); i >= 0; --i)
    		{
    			r.shlb();
    			r += c[i];
    			if (r.Comp(rhs) < 0)
    				q.c[i] = 0;
    			else
    			{
    				_l = 0, _r = Big_B;
    				for (; _l != _r;)
    				{
    					mid = _l + _r >> 1;
    					if ((rhs * mid).Comp(r) <= 0)
    						_l = mid + 1;
    					else
    						_r = mid;
    				}
    				q.c[i] = _l - 1, r -= rhs * q.c[i];
    			}
    		}
    		q.CrZ(), *this = r;
    		return q;
    	}
    
    	inline int Comp(const Int &rhs) const
    	{
    		if (c.size() != rhs.c.size())
    			return intcmp_(c.size(), rhs.c.size());
    		for (rg int i = c.size() - 1; i >= 0; --i)
    			if (c[i] != rhs.c[i])
    				return intcmp_(c[i], rhs.c[i]);
    		return 0;
    	}
    
    	friend inline Int operator+(const Int &lhs, const Int &rhs)
    	{
    		Int res = lhs;
    		return res += rhs;
    	}
    
    	inline friend Int operator-(const Int &lhs, const Int &rhs)
    	{
    		if (lhs < rhs)
    		{
    			putchar('-');
    			Int res = rhs;
    			return res -= lhs;
    		}
    		else
    		{
    			Int res = lhs;
    			return res -= rhs;
    		}
    	}
    
    	friend inline Int operator*(const Int &lhs, const Int &rhs)
    	{
    		Int res = lhs;
    		return res *= rhs;
    	}
    
    	friend inline std ::ostream &operator<<(std ::ostream &out, const Int &rhs)
    	{
    		if (rhs.c.size() == 0)
    			out << "0";
    		else
    		{
    			out << rhs.c.back();
    			for (rg int i = rhs.c.size() - 2; i >= 0; --i)
    				out << std ::setfill('0') << std ::setw(Big_L) << rhs.c[i];
    		}
    		return out;
    	}
    
    	friend inline std ::istream &operator>>(std ::istream &in, Int &rhs)
    	{
    		static char s[100000];
    		in >> s + 1;
    		int Len = strlen(s + 1);
    		int v = 0;
    		LL r = 0, p = 1;
    		for (rg int i = Len; i >= 1; --i)
    		{
    			++v;
    			r = r + (s[i] - '0') * p, p *= 10;
    			if (v == Big_L)
    				rhs.c.push_back(r), r = 0, v = 0, p = 1;
    		}
    		if (v != 0)
    			rhs.c.push_back(r);
    		return in;
    	}
    
    	friend inline bool operator<(const Int &lhs, const Int &rhs)
    	{
    		return lhs.Comp(rhs) < 0;
    	}
    
    	friend inline bool operator>(const Int &lhs, const Int &rhs)
    	{
    		return lhs.Comp(rhs) > 0;
    	}
    
    #undef rg
    } sum[100010], ans;
    
    int n;
    
    LL a[100010];
    //*===================================自定义函数*/
    
    //*=======================================主函数*/
    signed main()
    {
    	// freopen("a.in", "r", stdin);
    	// freopen("a.out", "w", stdout);
    	n = read();
    	for (int i = 1; i <= n; i++)
    		cin >> a[i];
    
    	for (int i = 1; i <= n; i++)
    	{
    		sum[i] = 1;
    		for (int j = 1; j <= a[i]; j++)
    			sum[i] *= j;
    		ans += sum[i];
    	}
    	//	for(int i=1;i<=n;i++)
    	//		ans=ans+sum[i];
    
    	cout << ans;
    	return 0;
    }
    
    

    正解思路

    吾即为真理。

    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <cmath>
    #include <iostream>
    #include <algorithm>
    #include <map>
    #include <set>
    #include <queue>
    #include <vector>
    using namespace std;
    typedef long long ll;
    typedef unsigned int uint;
    typedef unsigned long long ull;
    typedef pair<int, int> PII;
    #define fi first
    #define se second
    #define MP make_pair
    
    int read()
    {
        int v = 0, f = 1;
        char c = getchar();
        while (c < 48 || 57 < c)
        {
            if (c == '-')
                f = -1;
            c = getchar();
        }
        while (48 <= c && c <= 57)
            v = (v << 3) + v + v + c - 48, c = getchar();
        return v * f;
    }
    
    int n;
    
    struct B
    {
        int a[500], len;
        B()
        {
            for (int i = 0; i < 500; i++)
                a[i] = 0;
            len = 0;
        }
    } fac[200];
    
    B operator+(const B &a, const B &b)
    {
        B c;
        c.len = max(a.len, b.len);
        for (int i = 0; i <= c.len; i++)
            c.a[i] = a.a[i] + b.a[i];
        for (int i = 0; i <= c.len; i++)
            if (c.a[i] >= 10)
            {
                c.a[i + 1]++;
                c.a[i] -= 10;
            }
        if (c.a[c.len + 1])
            c.len++;
        return c;
    }
    
    B operator*(const B &a, const int &b)
    {
        B c;
        c.len = a.len;
        for (int i = 0; i <= c.len; i++)
            c.a[i] = a.a[i] * b;
        for (int i = 0; i <= c.len + 10; i++)
        {
            c.a[i + 1] += c.a[i] / 10;
            c.a[i] %= 10;
        }
        for (int i = c.len + 10; i >= 0; i--)
            if (c.a[i])
            {
                c.len = i;
                break;
            }
        return c;
    }
    
    int main()
    {
        freopen("a.in", "r", stdin);
        freopen("a.out", "w", stdout);
        n = read();
        fac[0].a[0] = 1;
        for (int i = 1; i <= 100; i++)
            fac[i] = fac[i - 1] * i;
        B ans;
        while (n--)
            ans = ans + fac[read()];
        for (int i = ans.len; i >= 0; i--)
            printf("%d", ans.a[i]);
        puts("");
    }
    

    T2

    考场思路

    没有思路。。。

    一个半小时的时间推结论,发现只有 (k leq 2) 时情况满足结论,果断特判想嫖走 (30 pts)

    果然还是太年轻了。。

    一开始读错题?以为任意一列或任意一排不出现相同的颜色排列顺序才算合法,然鹅死活搞不出样例来,后来经过 K 神提醒才发现颜色组类不同就可以啦。

    仍旧码不出来。。。

    弃了弃了去看 (T3),临近交卷 (10) 分钟才悟到这原来是容斥
    ,容斥我也不会哇 (((以后上课再不睡觉了qwq


    部分样例的手胡过程

    正解思路

    容斥。

    枚举有 (i)(j) 列同色的方案数,并乘上 ((-1)^{i+j}) 加入答案。

    (f(i, j))(i)(j) 列同色,同色的行列所能取的颜色方案数。

    (i= 0,j= 0) 时,(f(i, j) = 1)

    (i= 0, j >0) 时,(f(i, j) =k^j)

    (i>0, j= 0) 时,(f(i, j)=k^i)

    (i >0, j >0) 时,(f(i, j) =k)

    答案为

    [sum limits_{i=0}^{n} sum limits_{j=0}^{m} (-1)^{i+j} C_{n}^{i} C_{m}^{j} cdot f(i, j) cdot k^{(n-i)(m-j)} ]

    对于 (i=0)(j=0) 的情况可以暴力计算,考虑 (i)(j) 都大于 (0) 的情况。

    [egin{aligned} &k sum_{i=1}^{n} sum_{j=1}^{m}(-1)^{i+j} C_{n}^{i} C_{m}^{j} cdot k^{(n-i)(m-j)} \ = &k sum_{i=1}^{n}(-1)^{i} C_{n}^{i} sum_{j=1}^{m}(-1)^{j} C_{m}^{j} cdot k^{(n-i)(m-j)} \ = &k sum_{i=1}^{n}(-1)^{i} C_{n}^{i} sum_{j=1}^{m}(-1)^{j} C_{m}^{j} cdotleft(k^{n-i} ight)^{m-j} \ = &k sum_{i=1}^{n}(-1)^{i} C_{n}^{i}left(left(k^{n-i}-1 ight)^{m}-left(k^{n-i} ight)^{m} ight) end{aligned} ]

    就可以利用快速幂计算了。

    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <cmath>
    #include <iostream>
    #include <algorithm>
    #include <map>
    #include <set>
    #include <queue>
    #include <vector>
    using namespace std;
    typedef long long ll;
    typedef unsigned int uint;
    typedef unsigned long long ull;
    typedef pair<int, int> PII;
    #define fi first
    #define se second
    #define MP make_pair
    
    ll read()
    {
        ll v = 0, f = 1;
        char c = getchar();
        while (c < 48 || 57 < c)
        {
            if (c == '-')
                f = -1;
            c = getchar();
        }
        while (48 <= c && c <= 57)
            v = (v << 3) + v + v + c - 48, c = getchar();
        return v * f;
    }
    
    const ll MOD = 998244353, MOD2 = MOD - 1;
    const int N = 1010000;
    
    ll n, m, K;
    
    ll fac[N], inv[N];
    
    ll pw(ll a, ll b)
    {
        a = (a % MOD + MOD) % MOD;
        b = (b % MOD2 + MOD2) % MOD2;
        ll re = 1;
        while (b)
        {
            if (b & 1)
                re = re * a % MOD;
            a = a * a % MOD;
            b >>= 1;
        }
        return re;
    }
    
    ll C(int n, int m)
    {
        if (n < 0 || m < 0 || n - m < 0)
            return 0;
        return fac[n] * inv[m] % MOD * inv[n - m] % MOD;
    }
    
    int main()
    {
        freopen("b.in", "r", stdin);
        freopen("b.out", "w", stdout);
        fac[0] = 1;
        for (ll i = 1; i <= 1000000; i++)
            fac[i] = fac[i - 1] * i % MOD;
        inv[0] = inv[1] = 1;
        for (ll i = 2; i <= 1000000; i++)
            inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;
        for (ll i = 1; i <= 1000000; i++)
            inv[i] = inv[i - 1] * inv[i] % MOD;
        n = read(), m = read(), K = read();
        ll ans = pw(K, n * m);
        for (ll i = 1; i <= n; i++)
            if (i & 1)
                ans = (ans - C(n, i) * pw(K, i) % MOD * pw(K, (n - i) * m) % MOD + MOD) % MOD;
            else
                ans = (ans + C(n, i) * pw(K, i) % MOD * pw(K, (n - i) * m) % MOD) % MOD;
        for (ll i = 1; i <= m; i++)
            if (i & 1)
                ans = (ans - C(m, i) * pw(K, i) % MOD * pw(K, (m - i) * n) % MOD + MOD) % MOD;
            else
                ans = (ans + C(m, i) * pw(K, i) % MOD * pw(K, (m - i) * n) % MOD) % MOD;
        for (ll i = 1; i <= n; i++)
            if (i & 1)
                ans = (ans - C(n, i) * K % MOD * ((pw(pw(K, n - i) - 1, m) - pw(K, (n - i) * m) + MOD) % MOD) % MOD + MOD) % MOD;
            else
                ans = (ans + C(n, i) * K % MOD * ((pw(pw(K, n - i) - 1, m) - pw(K, (n - i) * m) + MOD) % MOD) % MOD) % MOD;
        printf("%lld
    ", ans);
        return 0;
    }
    

    T3

    考场思路

    面向数据编程!!!

    样例输入 1 10 6 2 ,输出 53 拿出计算器一摁,发现 (2^6 - (1+10) = 53)

    ??????????

    猜到了结论???

    算了算了没时间了就这么交吧。。。祈祷不出错!!

    果不其然是错的。。

    /*
    
    Name:
    
    Solution:
    
    
    By Frather_
    
    */
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    
    #define int long long
    #define InF 0x3f3f3f3f
    
    #define kMod 998244353
    
    using namespace std;
    //*=========================================快读*/
    int read()
    {
    	int x = 0, f = 1;
    	char c = getchar();
    	while (c < '0' || c > '9')
    	{
    		if (c == '-')
    			f = -1;
    		c = getchar();
    	}
    	while (c >= '0' && c <= '9')
    	{
    		x = (x << 3) + (x << 1) + (c ^ 48);
    		c = getchar();
    	}
    	return x * f;
    }
    //*=====================================定义变量*/
    int l,r,k,n;
    //*===================================自定义函数*/
    int Qpow(int a,int p)
    {
    	int res = 1;
    	while(p)
    	{
    		if(p & 1)
    			res = res * a % kMod;
    		a = a * a % kMod;
    		p >>= 1;
    	}
    	return res;
    }
    //*=======================================主函数*/
    signed main()
    {
    	// freopen("c.in","r",stdin);
    	// freopen("c.out","w",stdout);
    	l=read();
    	r=read();
    	k=read();
    	n=read();
    	printf("%lld
    ",(Qpow(n , k) - r - l)%kMod);
    	// fclose(stdin);
    	// fclose(stdout);
    	return 0;
    }
    

    正解思路

    由裴蜀定理得,对于一个确定的 (B) ,答案为

    [sum limits_{i_{1} mid B} sum limits_{i_{2} mid B} cdots sum limits_{i_{n} mid B}left[g c dleft(i_{1}, i_{2}, cdots, i_{n}, K ight)=1] ight. ]

    由此,只需要对 (L sim R) 中每个 (B) 计算上述公式的答案即可。

    若记答案为 (f(i)) ,由于每个质因子独立,则其为积性函数。

    如果 (B) 的质因数分解式中含有 (p^{c}) 这一项,那么单独考虑这一质因子,如果 (K) 的质因数分解式中含有 (p^{d}), 那么答案为 (sum limits_{i_{1}=0}^{c} sum limits_{i_{2}=0}^{c} cdots sum limits_{i_{n}=0}^{c} left[ min left(i_{1}, i_{2}, cdots, i_{n}, d ight)=0 ight])

    即如果 (d>0), 为((c+1)^{n}-c^{n}) ;否则为 ((c+1)^{n})

    现在已经对所有质数的幂求出函数值了,利用师法,可以求出所有函数值。

    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <cmath>
    #include <iostream>
    #include <algorithm>
    #include <map>
    #include <set>
    #include <queue>
    #include <vector>
    using namespace std;
    typedef long long ll;
    typedef unsigned int uint;
    typedef unsigned long long ull;
    typedef pair<int, int> PII;
    #define fi first
    #define se second
    #define MP make_pair
    
    ll read()
    {
        ll v = 0, f = 1;
        char c = getchar();
        while (c < 48 || 57 < c)
        {
            if (c == '-')
                f = -1;
            c = getchar();
        }
        while (48 <= c && c <= 57)
            v = (v << 3) + v + v + c - 48, c = getchar();
        return v * f;
    }
    
    const int N = 10001000;
    const ll MOD = 998244353;
    int L, R;
    ll K, m;
    ll mi[200];
    int pr[N], a[N];
    ll f[N];
    
    ll pw(ll a, ll b)
    {
        ll re = 1;
        while (b)
        {
            if (b & 1)
                re = re * a % MOD;
            a = a * a % MOD;
            b >>= 1;
        }
        return re;
    }
    
    int main()
    {
        freopen("c.in", "r", stdin);
        freopen("c.out", "w", stdout);
        L = read(), R = read(), K = read(), m = read();
        for (int i = 0; i <= 100; i++)
            mi[i] = pw(i, m);
        for (int i = 2; i <= 10000000; i++)
        {
            if (!a[i])
            {
                pr[++pr[0]] = i;
                a[i] = 1;
            }
            for (int j = 1; j <= pr[0] && 1LL * i * pr[j] <= 10000000; j++)
                if (i % pr[j] == 0)
                {
                    a[i * pr[j]] = a[i];
                    break;
                }
                else
                    a[i * pr[j]] = i;
        }
        for (int i = 1; i <= pr[0]; i++)
            if (K % pr[i] == 0)
            {
                for (ll j = 1, t = pr[i]; t <= 10000000; j++, t *= pr[i])
                    f[t] = (mi[j + 1] - mi[j] + MOD) % MOD;
            }
            else
            {
                for (ll j = 1, t = pr[i]; t <= 10000000; j++, t *= pr[i])
                    f[t] = mi[j + 1];
            }
        f[1] = 1;
        for (int i = 2; i <= 10000000; i++)
            if (a[i] > 1)
                f[i] = f[a[i]] * f[i / a[i]] % MOD;
        for (int i = 2; i <= 10000000; i++)
            f[i] = (f[i - 1] + f[i]) % MOD;
        printf("%lld
    ", (f[R] - f[L - 1] + MOD) % MOD);
    }
    
    

    写在最后

    题目真的很有个性。

    我没读懂 T2 ,另外二位没读懂 T3 ,题面是真的不错不错。

  • 相关阅读:
    Node.js NPM 包(Package)
    Node.js NPM 作用
    Node.js NPM 介绍
    Node.js NPM 教程
    Node.js NPM 教程
    Node.js 发送Email
    Node.js 上传文件
    Node.js 事件
    Node.js NPM
    Node.js 文件系统模块
  • 原文地址:https://www.cnblogs.com/Frather/p/14757486.html
Copyright © 2011-2022 走看看