题目概述
题目名称要不要这么奇葩而且和题面没有半毛钱关系啊,我上交题目都以为自己TLE了。
给出 n n 个数 ,现在需要构造 ai a i 使得:
- ai mod ci>0 a i m o d c i > 0 。
- ai and ai+1=0 a i a n d a i + 1 = 0 。
解题报告
先不考虑 ci c i ,那么我们很容易想到DP: f[i][j] f [ i ] [ j ] 表示前 i i 个数第 个是 j j 的方案数。
直接枚举肯定不科学,观察 ,其实是个经典的高维前缀和求超集( y y 是 的超集且 y and z=0 y a n d z = 0 意味着 x and z=0 x a n d z = 0 ,即 y y 包含 )问题。
但如何处理 ci c i ?其实就在每次转移之后把 j mod ci=0 j m o d c i = 0 的状态 j j 赋值为 就行了。
示例程序
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=50,maxs=32768,MOD=1e9;
int te,n,m,c[maxn+5],f[maxn+5][maxs+5],ans;
inline void AMOD(int &x,int tem) {if ((x+=tem)>=MOD) x-=MOD;}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
for (scanf("%d",&te);te;te--)
{
scanf("%d%d",&n,&m);for (int i=1;i<=n;i++) scanf("%d",&c[i]);
memset(f,0,sizeof(f));for (int s=0;s<(1<<m);s++) if (s%c[1]) f[1][s]=1;
for (int i=2;i<=n;i++)
{
for (int s=0;s<(1<<m);s++) f[i][s]=f[i-1][s^((1<<m)-1)];
for (int j=0;j<m;j++)
for (int s=0;s<(1<<m);s++) if (!(s&(1<<j)))
AMOD(f[i][s],f[i][s|(1<<j)]);
for (int s=0;s<(1<<m);s++) if (!(s%c[i])) f[i][s]=0;
}
ans=0;for (int s=0;s<(1<<m);s++) if (s%c[n]) AMOD(ans,f[n][s]);
printf("%d\n",ans);
}
return 0;
}