按位dp,将原来的n个数扩展为 2*n-1 个数
#include <cstdio> #include <cmath> #include <algorithm> using namespace std; const int MAXN = 50005; const int MAXK = 205; int num[MAXN*2], nwei[MAXN*2], dp[2][MAXK], swei[MAXN*2]; int n, k; int ten[MAXN*4]; void getwei(int i) { int nm = num[i], res = 0; while (nm) { ++res; nm /= 10; } nwei[i] = res; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif ten[0] = 1; while (scanf("%d%d", &n, &k) != EOF) { int nn = 2*n -1; for (int i = 1; i<= n; ++i) { scanf("%d", num+i); getwei(i); } for (int i = n+1; i<= nn; ++i) { num[i] = num[i-n]; nwei[i] = nwei[i-n]; } for (int i = 1; i<= 4*n; ++i) { ten[i] = ten[i-1]*10%k; } memset(dp, 0, sizeof dp); int sum = 0, nt = 0, res = 0; for (int i = n; i> 0; --i) { sum = (num[i]*ten[nt] + sum)%k; nt += nwei[i]; ++dp[0][sum]; } res += dp[0][0]; --dp[0][sum]; for (int i = 0; i< k; ++i) { dp[1][(i*ten[nwei[n+1]]+num[n+1])%k] += dp[0][i]; } int cur = 1; for (int i = n+1; i<= nn; ++i, cur=1-cur) { dp[cur][num[i]%k]++; res += dp[cur][0]; sum = ((sum - ten[(nt-nwei[i-n])]*num[i-n]%k + k)*ten[nwei[i]] + num[i])%k; nt = nt-nwei[i-n]+nwei[i]; --dp[cur][sum]; memset(dp[1-cur], 0, 4*MAXK); for (int j = 0; j< k; ++j) { dp[1-cur][(j*ten[nwei[i+1]]+num[i+1])%k] += dp[cur][j]; } } printf("%d\n", res); } return 0; }