T^TOJ2332 电灯泡(容斥定理)
【题意】
V_Dragon有n栈电灯泡,编号为1-n,每个灯泡都有一个开关。那么问题来了
-
所有灯泡初始时为不亮的
-
V_Dragon分别进行三次操作
-
每次操作他都选一个质数x,将编号为x和x的整数倍的灯泡的开关都拨动一下(如果灯为亮,那么拨动以后灯为不亮,如果灯不亮,拨动以后变为亮)
求最后亮着的灯的数量
【解题思路】
画一下图可以知道最后亮着的灯泡的数量如下图所示
将集合A表示为被a整除的数,集合B为被b整除的数,集合C为被c整除的数。
阴影部分的面积求法:S-AB-AC-BC+3ABC
而S=A+B+C-AB-AC-BC+ABC 整理得阴影部分面积为A+B+C-2*(AB+AC+BC)+4*ABC
【代码】
#include<bits/stdc++.h>
using namespace std;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,a,b,c;
scanf("%d",&n);
scanf("%d%d%d",&a,&b,&c);
int sum=n/a+n/b+n/c-2*(n/a/b+n/a/c+n/b/c)+4*(n/a/b/c);//因为a,b,c都为质数所以直接相除即可,若不是质数,应该乘上最大公约数
printf("%d\n",sum);
}
return 0;
}
hdu6143 Killer Names(容斥定理)
【题意】
用m个字符组合名字,名字中有姓和名分别为长度为n的字符串,姓和名中的字符不能相同,但姓中的字符可以相同,名中的字符也可以相同。
【解题思路】
用f[i]表示姓中含有i个字符
f[1]=1
f[2]=2^n-C[2][1]*f[1](这里需要运用容斥定理,减去姓中含有1个字符的情况)
f[3]=3^n-C[3][2]*f[2]-C[3][1]*f[1]
f[i]=i^n-(C[i][1]*f[1]+C[i][2]*f[2]+...C[i][i-1]*f[i-1])
姓中的字符搞定后名中的字符就简单了,最后所有方案数为 C(m,i)*f[i]*(m-i)^n ,1<=i<=m
【代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=2005;
const int mod=1e9+7;
LL n,m,c[maxn][maxn],f[maxn];
void zuhe()
{
memset(c,0,sizeof(c));
for(int i=1;i<maxn;i++)
{
c[i][0]=c[i][i]=1;
for(int j=1;j<i;j++)
{
c[i][j]=c[i-1][j]+c[i-1][j-1];
c[i][j]%=mod;
}
}
}
LL quickpow(LL a,LL b)
{
LL ans=1;
while(b)
{
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans%mod;
}
int main()
{
int T;
zuhe();
scanf("%d",&T);
while(T--)
{
scanf("%lld%lld",&n,&m);
memset(f,0,sizeof(f));
f[1]=1;
//将递推数组打印出,运用容斥定理去重
for(int i=2;i<=n;i++)
{
f[i]=quickpow(i,n);
//printf("f[i]1=%lld\n",f[i]);
for(int j=1;j<i;j++)
{
f[i]=(f[i]-c[i][j]*f[j])%mod;
if(f[i]<0)f[i]=(f[i]+mod)%mod;
//printf("f[i]2=%lld\n",f[i]);
}
}
LL ans=0;
//求和:C(m,i)*f[i]*(m-i)^n
for(int i=1;i<=m;i++)
{
ans+=c[m][i]%mod*f[i]%mod*quickpow(m-i,n)%mod;
}
printf("%lld\n",ans%mod);
}
return 0;
}
NYOJ417 死神来了(鸽巢原理)
【题意】
在1~n个数中,随机取m个数,问在这m个数中是否一定存在一个数是另一个数的倍数,是则回答“YES",否则”NO"。
【解题思路】
考虑最小的倍数是2点情况,那么n个数中,当m≤n/2,考虑最坏的情况,n全部随机到了 n/2-n 在这个区间内所有数都是互质的。比如n=100 m=50 那么显而易见,最坏的情况选的是51-100,这些数都没有公因数,但如果 m=51的时候,最坏也会选中 50-100 50的两倍是100。同理,如果为n奇数,例如101 在 1-101之间,那么最坏情况m只有为52才能构成。
【代码】
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
int ans=n/2+(n&1);
if(m>ans)printf("YES\n");
else printf("NO\n");
}
return 0;
}