Comet OJ - Contest #3子序列子序列子序列…
#include<bits/stdc++.h>
#define per(i,a,b) for(int i = (a);i <= (b);++i)
#define rep(i,a,b) for(int i = (a);i >= (b);--i)
using namespace std;
const int maxn = 5e3;
const int mod = (1e9 + 7);
int n = 0,m = 0;
int a[maxn+10],dp[2][14][maxn+10],f[2][maxn+10];
int cal(int& x){
int res = 0;
while(x % 2 == 0){
++res;
x >>= 1;
}
return res;
}
inline void upd(int& x){
if(x >= mod){
x -= mod;
}
}
void solve(){
int nf = 0,tm = m,em = m;
int c = cal(em);
dp[nf][0][0] = 1;
per(i,1,n){
nf ^= 1;
tm = m;
dp[nf][0][0] = 0;
//per(j,1,c){//初始化
for(int j = 1;j <= c && j <= i;++j){
per(k,0,tm-1){
dp[nf][j][k] = 0;
}
}
dp[nf][0][0] += dp[nf^1][0][0]; dp[nf][1][a[i]] += dp[nf^1][0][0];
tm = m;
for(int j = 1;j <= c && j <= i-1;++j){//两个灯饰条件
per(k,0,tm-1){
dp[nf][j][k] += dp[nf^1][j][k]; upd(dp[nf][j][k]);
dp[nf][j+1][(k+a[i]) % (tm>>1)] += dp[nf^1][j][k]; upd(dp[nf][j+1][(k + a[i]) % (tm>>1)]);
}
tm >>= 1;
}
}
int ans = 0;
tm = m;
per(j,1,c){//减去那些可以整除em的,但是比m小的方案
for(int k = em;k < tm;k += em){//不可以取等号,<表示上面那种情况
ans += (mod - dp[nf][j][k]); upd(ans);
}
tm >>= 1;//tm /2来控制2次方个数
}
f[0][0] = 1;
nf = 0;
per(i,1,n){//一起算%em==0的方案,由于前面减去了 些可以整除em的,但是比m小的方案
nf ^= 1; //所以最后就是结果
per(j,0,em-1){
f[nf][j] = (f[nf^1][j] + f[nf^1][(j-a[i] + m) % em]); upd(f[nf][j]);
}
}
f[nf][0] += (mod - 1); upd(f[nf][0]);//减去f[0][0]
ans += (f[nf][0]); upd(ans);
ans = ((ans % mod) + mod) % mod;
printf("%d\n",ans);
}
int main(){
scanf("%d %d",&n,&m);
per(i,1,n){
scanf("%d",a+i);
}
solve();
return 0;
}