題目連結:
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;
}