题意:
给你 n n n (不超过2e6) 个数,和一个数 r r r,问你有多少种方案,使得你取出某个子集,能够让它们的乘积 mod 2017等于 r r r。
解:
由于2017有5这个原根,考虑 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示到第 i i i 个点后取模结果为 j j j 的数的个数,每次转移就是 d p [ i ] [ j ∗ x ] + = d p [ i − 1 ] [ j ] dp[i][j∗x]+=dp[i−1][j] dp[i][j∗x]+=dp[i−1][j], 因为转化为加法后,能够快速求得值, 最后的结果要对 2 2 2 取模,因此用 bitset 做。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
#include <sstream>
#include <cctype>
#include <ctime>
#include <bitset>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int N = 2e6+5;
bitset <2016> bi;
int a[N], b[2020];
int main()
{
int tmp = 1;
for(int i = 1; i < 2017; ++i){
tmp = (tmp*5) % 2017;
b[tmp] = i;
}
b[1] = 0;
int n, r;
while(scanf("%d%d", &n, &r) != EOF){
bi.reset();
bi.set(b[1]);
for(int i = 1; i <= n; ++i){
scanf("%d", &a[i]);
bi ^= (bi << b[a[i]]) ^ (bi >> (2016-b[a[i]]));//乘a[i]有两种可能,超出2017和未超出2017
}
cout << bi[b[r]] << '\n';
}
return 0;
}