题目链接:
https://ac.nowcoder.com/acm/contest/548/F
思路:
尽量选伤害对手而不伤害自己的武器,如果这些武器用完了,就选既伤害自己又伤害对手的武器。
选不伤害自己的武器其实就是选不是2,3...m的倍数,这其实可以进一步推出选不是2--m中的素数的倍数,因为每一个数都可以被表示成素数相乘。
找不是2-m中素数的倍数其实可以用n减去2-m素数的并集,这里就需要用容斥定理了。
可以通过dfs来取容斥定理所需要的集合,然后套用容斥定理公式即可。
还有几个优化:
(1)如果自身血量==0,则直接算输。
(2)如果自己的武器数小于敌人血量则算输。
求出总数sum之后,n-sum就是不伤害自己的总数。
如果n-sum>=k赢。
否则则需要伤害自己的武器补伤害,如果伤害不够或者补着补着自己就死了则算输。
否则算赢
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int t;
ll k,q,n,m;
int su[15]={0,2,3,5,7,11,13,17,19};
int vis[15];
int re[15];
ll sum;
int r;
void dfs(int loc,int nn,int nnum)
{
if(nnum==nn)
{
ll tsum=1;
for (int i=0;i<nn;i++)
{
tsum*=su[re[i]];
}
if(nn%2) sum=sum+n/tsum;
else sum=sum-n/tsum;
return;
}
for (int i=loc;i<=r;i++)
{
if(!vis[i])
{
vis[i]=1;
re[nnum]=i;
dfs(i+1,nn,nnum+1);
vis[i]=0;
}
}
}
int main()
{
while(scanf("%d",&t)!=EOF)
{
while(t--)
{
scanf("%lld%lld%lld%lld",&k,&q,&n,&m);
sum=0;
if(k==0||q>n)
{
printf("QAQ\n");
continue;
}
r=0;
for (int i=1;i<=8;i++)
{
if(m<su[i]) break;
r++;
}
for (int i=1;i<=r;i++)
{
memset (vis,0,sizeof(vis));
dfs(1,i,0);
}
if(n-sum>=q)
{
printf("Yes\n");
continue;
}
q=q-(n-sum);
if(sum<q||k<q)
{
printf("QAQ\n");
}
else
{
printf("Yes\n");
}
}
}
return 0;
}