2024牛客多校1 A

A- A Bit Common

这题感觉只需要考虑一下如何去重即可。

我们可以枚举非空子序列的大小,为了防止重复,我们就需要考虑如何能使长度为i的非空子序列唯一合法。很明显的一点是当当前子序列合法时,任何一个2进制最低位为1的数加入到当前子序列中,序列的与值仍然为1。也就是说,假设当前长度为i的子序列合法,那么剩下的n-i个数的二进制位最低位都必须是0,否则假设n-i个数里有1个数二进制最低位为1,那么我们就会多算长度为i+1时的贡献。

那么答案就很明显了,从n个位置选择i个位置,每个二进制位有0和1两种填法,为了使枚举的i个数合法,那么除了最低位全1,其他每一位i个数都不能全选1,共m-1位,则有\binom{n}{i}\left ( 2^{i}-1 \right )^{m - 1},剩下n-i个数最低位一定是零,剩下m-1位随意则有\left ( 2^{n-i} \right )^{m - 1}

答案则为\sum_{i=1}^{n}\binom{n}{i}\left ( 2^{i}-1 \right )^{m - 1}\left ( 2^{n-i} \right )^{m - 1}

注意到模数可能是合数,不能使用逆元,因此可以使用递推求组合数,赛时忘记了这个做法,我用的是质因数分解计算的组合数。

#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
#define rep(x,a,b) for(int x=a;x<=b;x++)
#define pre(x,a,b) for(int x=a;x>=b;x--)
#define ac puts("Yes")
#define wa puts("No")
#define ll long long
#define int long long
#define endl "\n"
#define pb push_back
#define pii pair<ll, ll>
#define de cout<<1;
#define mem(a,x) memset(a,x,sizeof a)
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define ull unsigned long long
#define eps 1e-6
#define RI register int
#define CI const int&
using namespace std;
const int N = 1e6 + 20;
int n, m, k, mod1;
int st[N] = {1, 1};
ll phi[N], idx;
ll c[N];
void su()
{
	rep(i, 2, 1000000)
	{
		if(!st[i]) phi[++idx] = i;
		rep(j, 1, idx)
		{
			if(phi[j] * i > 1000000) break;
			st[i * phi[j]] = 1;
			if(i % phi[j] == 0) break;
		}
	}
}
ll qmi(ll a, ll b)
{
	ll base = 1;
	while(b)
	{
		if(b & 1) base = base * a % mod1;
		b >>= 1;
		a = a * a % mod1;
	}
	return base;
}
void jc()
{
    map<int, int>mp;
    int now = n;
    c[0] = 1;
    c[n] = 1;
    rep(i, 1, n / 2)
    {
        int nn = now;
        for(int j = 1; j <= idx && phi[j] * phi[j] <= nn; j ++ )
        {
            int cnt = 0;
            while(nn % phi[j] == 0) cnt ++ , nn /= phi[j];
            if(cnt) mp[phi[j]] += cnt;
        }
        if(nn > 1) mp[nn] ++ ;
        nn = i;
        for(int j = 1; j <= idx && phi[j] * phi[j] <= nn; j ++ )
        {
            int cnt = 0;
            while(nn % phi[j] == 0) cnt ++ , nn /= phi[j];
            if(cnt) mp[phi[j]] -= cnt;
        }
        if(nn > 1) mp[nn] -- ;
        now -- ;
        ll res = 1;
        for(auto it : mp)
        {
            res = (res * qmi(it.first, it.second) % mod1) % mod1;
        }
        c[i] = res;
        c[n - i] = res;
    }
}
void solve()
{
	cin >> n >> m >> mod1;
    jc();
    ll ans = 0;
    rep(i, 1, n)
    {
        ll res = 0;
        res = ((c[i] % mod1 * qmi(((qmi(2, i) - 1ll + mod1) % mod1), m - 1) % mod1) % mod1 * qmi(qmi(2, n - i), m - 1) % mod1) % mod1;
        ans = (ans + res) % mod1;
    }
    cout << ans;
}
signed main()
{
	IOS;
	int t;
	t = 1;
    su();
	// cin >> t;
	while(t -- )
	{
		solve();
	}
	return 0;
}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值