时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
Special Judge, 64bit IO Format: %lld
题目描述
Bobo has n integers a1,a2,…,ana_1, a_2, \dots, a_na1?,a2?,…,an?.
He would like to choose some of the integers and calculate their product (the product of the empty set is defined as 1).
Bobo would like to know the number of products whose remainder divided by 2017 is r. As the exact number is too large, he only asks for the number modulo 2.
输入描述:
The input contains zero or more test cases and is terminated by end-of-file. For each case, The first line contains two integers n, r. The second line contains n integers a1,a2,…,ana_1, a_2, \dots, a_na1?,a2?,…,an?.* 1≤n≤2×1061 \leq n \leq 2\times 10^61≤n≤2×106 * 1≤r,a1,a2,…,an<20171 \leq r, a_1, a_2, \dots, a_n < 20171≤r,a1?,a2?,…,an?<2017 * The sum of n does not exceed 2×1062 \times 10^62×106.
输出描述:
For each case, output an integer which denotes the parity.
示例1
输入
3 6 2 3 4 4 1 1 1 2016 2016
输出
1 0
本题需要用到数论中原根的知识再结合bitset来优化dp。
首先由题意可以想到一个裸的dp, dp(i,j)表示前i个数,选出来的乘积模2017为j的方案数,转移方程为,初始状态为dp[0][1]=1。然而总状态数为大约2e9,显然会T。
因为只需要求方案数模2,或许我们可以联想到位运算异或,如果能将一层转移(i相同的转移)转化为常数次bitset的操作,计算规模就能降到 ,即可通过本题。
要想只通过常数次bitset操作转移,那么我们希望转移是连续的,比如从[l,r]转移到[x,y],其中r-l+1==y-x+1,即区间长度相同,且大小关系也一一对应,对于这样的区间只需要一次bitset操作即可完成转移。
2017是一个奇素数,原根必存在。对于一个奇素数p,模p的原根可以在指数取[1,p-1]区间时,模p得到[1,p-1]的所有值。
模2017有原根5,那么我们可以用来表示模2017为x的数,那么乘法就可以转化为指数上的加法,则我们可以通过映射,使得转移是连续的。
令dp(i,j)表示前i个数,选出来的乘积为的方案数,转移方程为
通过滚动数组,只需要一个bitset即可完成转移,有dp=dp^(dp<<I[a[i]])^(dp>>(2016-I[a[i]]))
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=2e6+5;
int n,r,I[2017],a[maxn];//5^I[i]%2017 equal i, 5 is 2017's 原根
bitset<2016> dp;//5^[0,2015]%2017 equal [1,2016]%2017
int main(){//freopen("in.txt","r",stdin);int tt=1;for(int i=0;i<2016;i++){I[tt]=i;tt=tt*5%2017;}while(~scanf("%d %d",&n,&r)){for(int i=1;i<=n;i++){scanf("%d",&a[i]);}dp.reset();dp.set(0);//no number was selectedfor(int i=1;i<=n;i++){//转移有两种:dp[i][j]=dp[i-1][j]+dp[i-1][j-I[a[i]]],后者又可拆为[0,2015-I[a[i]]]转移到[I[a[i]],2015],[2016-I[a[i]],2015]转移到[0,I[a[i]]]dp^=(dp<<I[a[i]])^(dp>>(2016-I[a[i]]));}cout<<dp[I[r]]<<"\n";}return 0;
}