【JZOJ 3823】【NOIP2014模拟9.9】遇见
2017-01-14 21:41
477 查看
Description
Zyh独自一人在街上漫步。Zyh相信不久后应该就可以和她一起漫步,可是去哪里寻找那个她呢?Zyh相信每个人都有一个爱情的号码牌,这个号码牌是一个n*n的矩阵。每个人都要在矩阵中选择若干个元素,使得每行每列都有奇数个数被选中,且选中的数字的乘积是完全平方数。每当选出了这若干个元素,他/她就能找到那个她/他。
Zyh想知道对于一个号码牌有多少种选择的方法,使得zyh能够不再孤独。由于这个数字很大,只要输出对1,000,000,007取模后的余数即可。
Data Constraint
第一类:对于30%的数据 n<=4 Aij<=10第二类:对于50%的数据 n<=10 n*n个数分解质因数后的不同素数个数不超过5个
第三类:对于80%的数据 n<=15 Aij<=1000000000
第四类:对于100%的数据 n<=30 Aij<=1000000000
在第三类(不属于第二类)的数据中 有10%的数据满足Aij都为同一个素数
Solution
这是我第一次打高斯消元,可一上来就是一道高斯消元异或方程组……我们可以把所有约束变成一道道异或方程。
1、对于每行每列都有奇数个数被选中的约束。我们可以把第i行的每个未知数配上一个系数1。举个例子,第i行的式子为x(i−1)∗n+1^x(i−1)∗n+2^……^xi∗n==1。列的情况类似。
2、对于最终要求完全平方,我们可以拆解成n个质因数的指数为偶数。所以我们可以将n*n个数每个未知数的系数为它最多是该质因数的几次幂的倍数,例如36就是2的2次幂的倍数,同时36是3的2次幂的倍数。每个质因数也同样可以列出一个式子。
最后只要将这些高斯消元一下即可。
一些小问题
1、要注意,我们找不到当前第i位为1的式子时,我们可以将一条无意义式子(即类似0^0^0^……^0=0)移上第i位。2、式子有可能无解。当最后你发现存在式子(类似0^0^0^……^0=1)时,则为无解。因为你不能什么都不选。
Code
#include<iostream> #include<cmath> #include<cstring> #include<cstdio> #include<algorithm> #define ll long long using namespace std; const int maxn=2005,maxn1=35,mo=1e5+5,mo1=1e9+7; int f[maxn][1000],n,i,t,j,k,l,a[maxn1][maxn1],num,h[mo],b[maxn],x,y,c[maxn],d[maxn],ans,p; void hash(int x){ int t=x%mo; while (h[t]!=x && h[t]) t=(t+1)%mo; if (!h[t]) h[t]=x,b[++b[0]]=x; } ll mi(int x){ if (x==1) return 2;if (!x) return 1; ll t=mi(x/2); if (x%2) return t*t%mo1*2%mo1;return t*t%mo1; } int main(){ // freopen("data.in","r",stdin); scanf("%d",&n); for (i=1;i<=n;i++) for (j=1;j<=n;j++) scanf("%d",&a[i][j]); t=a[1][1];k=0; for (i=1;i<=n;i++) for (j=1;j<=n;j++) if (a[i][j]==t) k++; if (k==n*n && t>1 && (n%2)){ printf("0\n"); return 0; } for (i=1;i<=n;i++){ for (j=(i-1)*n+1;j<=i*n;j++) f[i][j]=1; f[i][n*n+1]=1; } num=n; for (i=1;i<=n;i++){ ++num; for (j=i;j<=n*n;j+=n) f[num][j]=1; f[num][n*n+1]=1; } for (i=1;i<=n;i++) for (j=1;j<=n;j++){ t=sqrt(a[i][j]);l=a[i][j]; for (k=2;k<=t;k++){ if (k*k>l) break; if (l%k) continue; hash(k); while (!(l%k)) l/=k; } if (l>1) hash(l); } for (k=1;k<=b[0];k++){ ++num; for (i=1;i<=n;i++) for (j=1;j<=n;j++){ t=a[i][j];l=0; while (!(t%b[k])) t/=b[k],l++; f[num][(i-1)*n+j]=l%2; } f[num][n*n+1]=0; } while (num<n*n){++num; for (j=1;j<=n*n+1;j++) f[num][j]=f[1][j]; } for (j=1;j<=n*n;j++){ for (i=j;i<=num;i++) if (f[i][j]){ for (k=j;k<=n*n+1;k++) swap(f[i][k],f[j][k]); break; } for (i=j+1;i<=num;i++){ if (!f[i][j]) continue; for (k=j;k<=n*n+1;k++) f[i][k]=(f[i][k]^f[j][k]); } if (!f[j][j]){ t=1e9; for (i=j;i<=num;i++){ k=j; while (!f[i][k] && k<=n*n) k++; if (k==n*n+1) k=j-1; if (k<t) t=k,p=i; } for (k=j;k<=n*n+1;k++) swap(f[p][k],f[j][k]); } } for (j=num;j>=1;j--){ t=f[j][n*n+1]; if (!t) continue; for (k=1;k<=n*n;k++) if (f[j][k]) break; if (k==n*n+1){ printf("0\n");return 0; } } for (j=n*n;j>=1;j--){ t=f[j][n*n+1]; for (k=j+1;k<=n*n;k++) t=(t^(f[j][k]*c[k])); if (t) c[j]=1; else if (!f[j][j]) ans++; } ans=mi(ans); printf("%d\n",ans); }
相关文章推荐
- JZOJ 3823【NOIP2014模拟9.9】遇见
- JZOJ 3823. 【NOIP2014模拟9.9】遇见
- 【JZOJ3824】【NOIP2014模拟9.9】渴
- JZOJ 3822. 【NOIP2014模拟9.9】逆光
- JZOJ 3824【NOIP2014模拟9.9】渴
- 【NOIP2014模拟9.9】遇见
- 【JZOJ3824】【NOIP2014模拟9.9】渴
- db49 JZOJ 3928. 【NOIP2014模拟11.6】射击
- jzoj3775 [NOIP2014模拟8.15]因子的排列
- JZOJ 3775. 【NOIP2014模拟8.15】因子的排列
- [jzoj]3889. 【NOIP2014模拟10.25B组】序列问题(DP的各种方法+细节+详细分析)
- JZOJ 3804. 【NOIP2014模拟8.24】小X 的AK 计划
- JZOJ NOIP2014模拟 8.13
- JZOJ 3807 【NOIP2014模拟8.25】地砖铺设
- 【JZOJ3892】【NOIP2014模拟10.25A组】放棋子
- JZOJ 3809. 【NOIP2014模拟8.25】设备塔
- JZOJ 3813. 【NOIP2014模拟9.7】我要的幸福
- JZOJ 5354. 【NOIP2017提高A组模拟9.9】导弹拦截
- JZOJ 3929. 【NOIP2014模拟11.6】创世纪
- [jzoj3889]【NOIP2014模拟10.25B组】序列问题