容斥原理练习

问题 A: Indivisibility

题目描述
给一个数n,找出1 ~ n范围内不被2 ~ 10整除的数的个数
输入
一个数n
输出
1 ~ n范围内不被2 ~ 10整除的数的个数
样例输入 Copy
12
样例输出 Copy
2
提示
数据范围:1<=n<=10^18

思路:
一共有n个数,这个题我们很容易想到,只需要减去那些不符合条件的就可以了
2 ~ 10之间的数可以分成被2 3 5 7整除的数
所以问题就转化成减去被2 3 5 7整除的数
我们可以得到ans = n - n/2 - n/3 - n/5 - n/7
我们又发现有一些数可以被2 3 5 7中的两个数整除
但是这样的数在前面多减了一次
比如6,它既可以被2整除也可以被3整除,它在n/2中减去一次,在n/3中又减去一次,所以我们需要加回来
ans = ans + n/(2 * 3) + n/(2 * 5) + n/(2 * 7) + n/(3 * 5) + n/(3 * 7) + n/(5 * 7)
同理可以被2 3 5 7中三个数整除的数在第一次中减去三次,在第二次中又加回来三次,相当于没有改变,所以我们还需要减去这一部分
比如30,它可以被2 3 5整除,它在n/2 n/3 n/5中各减去一次,一共减了三次,又在 n/(2 * 3) n/(2 * 5) n/(3 * 5) 加回来三次,所以我们需要再减去一次才符合条件
ans = ans - n/(2 * 3 * 5) - n/(2 * 3 * 7) - n/(2 * 5 * 7) - n/(3 * 5 * 7)
最后我们再减去可以被2 3 5 7四个数整除的就可以了

ans = ans - n/(2 * 3 * 5 * 7)

ll n,ans;
int main()
{
    scanf("%lld",&n);
    ans = n-(n/2+n/3+n/5+n/7)+n/6+n/10+n/14+n/15+n/21+n/35-(n/30+n/42+n/70+n/105)+n/210;
    printf("%lld\n",ans);
    return 0;
}

问题 B: Kuroni and Impossible Calculation

题目描述

已知一个数组a[n],请计算式子:∏_{1≤i<j≤n}|ai−aj| 的值,其中1<=i,j<=n;我们可以认为,这一式子等价于 |a1−a2|⋅|a1−a3|⋅ … ⋅|a1−an|⋅|a2−a3|⋅|a2−a4|⋅ … ⋅|a2−an|⋅ … ⋅|an−1−an|

输入
第一行是n,m。第二行是n个整数:a[1],a[2]……a[n]
输出
输出 ∏1≤i<j≤n|ai−aj| %m的值
样例输入 Copy
3 12
1 4 5
样例输出 Copy
0
提示
数据范围: 2≤n≤2⋅10^5, 1≤m≤1000,0≤ai≤10^9

思路:
我们发现模数m很小所以这个题可以用到鸽笼原理
鸽笼原理 (抽屉原理) “如果有五个鸽子笼,养鸽人养了6只鸽子,那么当鸽子飞回笼中后,至少有一个笼子中装有2只鸽子。”
当n > m 的时候,一定存在a[i] ≡ a[j] (mod m),所以答案就是0
当n <= m 的时候,暴力解决就可以了

int n,m;
ll a[maxn];
int main()
{
	n = read(),m = read();
	for(int i=1;i<=n;i++)	cin >> a[i];
	ll ans = 1;
	if(n <= m)
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=i+1;j<=n;j++)
			{
				ans = (ans*abs(a[j]-a[i])%m) % m;
			}
		}
		cout << ans << endl;
	}
	else	printf("0\n");
	return 0;
}

问题 D: 排课表

题目描述
新学期伊始,作为玉米高中的教务主任W某,又要安排学生们的课程表了。

W某想要知道所有可能的排课表方案,于是他开始在纸上列举所有方案,然而在写满了一摞A4纸后,他发现可能的方案太多了——用尽玉米高中所有的A4纸都写不完。

W某最终放弃了列举所有方案的想法,但他对排课表的方案数产生了兴趣。他的组合数学不太好,所以他找到了正在玉米高中就读的你,请你帮帮TA。

简单地说,玉米高中共有T个班级。

对于其中一个班级i,这个班级每天要上mi节互不相同的课,一共有ni节课可供选择,但这ni节课不能随便安排,其中也有一些限制:

·有ai节课不能安排在第一节上
·有bi节课不能安排在最后一节上
·没有任何一节课既不能在第一节上又不能在最后一节上
你需要求出每个班级排课表的方案数除以998244353的余数。

输入
第1行包含一个正整数T,表示玉米高中的班级数。
第2行到第T+1行,每行包含四个整数,第i+1行的四个整数ni,mi,ai,bi,分别表示班级i可选的课程数,一天的课程数,不能在第一节上的课程数,不能在最后一节上的课程数。
输出
输出T行,第i行表示班级i的排课表方案数除以998244353的余数。
样例输入 Copy
【样例1】
1
3 2 0 1
【样例2】
1
5 3 1 1
样例输出 Copy
【样例1】
4
【样例2】
39
提示
样例1解释
设3节可选的课为a,b,c,其中c不能排在最后一节
4种排课表的方案分别为:ab,ba,ca,cb

所有测试数据满足
·1≤T≤104
·2≤mi≤ni≤105
·ai+bi≤ni

const int N = 100010;
const int mod = 998244353;
/** keep hungry and keep calm! **/

ll ans;
int t,n,m,a,b;
ll fac[N];//阶乘
ll ni[N];//逆元
ll power(ll a,ll b,ll p)//快速幂 
{
    ll ans = 1,base = a;
    while(b)
	{
        if(b & 1)
        //&运算当相应位上的数都是1时,该位取1,否则该为0
            ans = 1ll*ans*base % p;
        base = 1ll*base*base % p;
        b >>= 1;//十进制下每除10 整数位就退一位
    }
    return ans;
}

void init()
{
    fac[0] = 1;
    ni[0] = 1;
    for(int i=1; i<N; i++)
	{
        fac[i] = fac[i-1]*i % mod;//求阶乘 
        ni[i] = ni[i-1]*power(i,mod-2,mod) % mod;
    }
}

int main()
{
    init();
    cin >> t;
    while(t--)
    {
    	cin >> n >> m >> a >> b;
    	ans = (fac[n]%mod*ni[n-m]%mod-fac[n-1]%mod*ni[n-m]%mod*(a+b)%mod+fac[n-2]%mod*ni[n-m]%mod*a*b%mod) % mod;
    	if(ans < 0)	ans += mod;
    	cout << ans << endl;
	}
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你数过天上的星星吗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值