【高維字首和】SPOJ(TLE)[Time Limit Exceeded]題解
阿新 • • 發佈:2019-01-29
題目概述
題目名稱要不要這麼奇葩而且和題面沒有半毛錢關係啊,我上交題目都以為自己TLE了。
給出 個數 ,現在需要構造 使得:
- 。
- 。
解題報告
先不考慮 ,那麼我們很容易想到DP: 表示前 個數第 個是 的方案數。
直接列舉肯定不科學,觀察 ,其實是個經典的高維字首和求超集( 是 的超集且 意味著 ,即 包含 )問題。
但如何處理 ?其實就在每次轉移之後把 的狀態 賦值為 就行了。
示例程式
#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;
}