1. 程式人生 > >【高維字首和】SPOJ(TLE)[Time Limit Exceeded]題解

【高維字首和】SPOJ(TLE)[Time Limit Exceeded]題解

題目概述

題目名稱要不要這麼奇葩而且和題面沒有半毛錢關係啊,我上交題目都以為自己TLE了。

給出 n 個數 ci ,現在需要構造 ai 使得:

  1. aimodci>0
  2. aiandai+1=0

解題報告

先不考慮 ci ,那麼我們很容易想到DP: f[i][j] 表示前 i 個數第 i 個是 j 的方案數。

直接列舉肯定不科學,觀察 aiandai+1=0 ,其實是個經典的高維字首和求超集(yx 的超集且 yandz=0 意味著 xandz=0 ,即

y 包含 x )問題。

但如何處理 ci ?其實就在每次轉移之後把 jmodci=0 的狀態 j 賦值為 0 就行了。

示例程式

#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; }