tkdsheep-ZOJ2317
从 Trac 迁移的文章
这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。
原文章内容如下:
{{{
给N*M的格子,N非常大,M小于等于5,然后对格子黑白染色,使得任意一个2*2的区域的4个格子颜色不能完全相同,问总的方案数
很明显是矩阵乘法,dp[mask]来表示当前行,黑白染色状态是mask的情况下,有多少种方案,这个方案只与上一行的mask有关
然后逐一check两种mask之间是否合法,建立转移矩阵即可
然后此题的N是10^100
于是我用了JAVA来写蛋疼的大数。。非常蛋疼。。而且时限卡的很紧,优化不好就超时,模板我依然用的是好基友、前队友delta的矩阵乘法模板,在JAVA下面改了一下语法格式,也算练练手吧
另外此题中矩阵乘法尽量少用mod,我是参照shi哥的做法,最后才mod的,因为题中mod最大值为10000,所以用long就可以避免爆掉
shi哥的矩阵求幂写法也值得学习,代码中有注释
}}}
{{{
import java.util.*;
import java.math.*;
public class Main {
static int unit[]={1,2,4,8,16,32,64};
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
BigInteger N;
int M,P,i,j,k;
long c[][]=new long[32][32];
long ans[][]=new long[32][32];
long s[][]=new long[32][32];
int re=in.nextInt();
while(re>0){
re--;
N=in.nextBigInteger();
M=in.nextInt();
P=in.nextInt();
for(i=0;i<32;i++)
for(j=0;j<32;j++)
s[i][j]=c[i][j]=ans[i][j]=0;
for(i=0;i<unit[M];i++)
{
s[i][i]=1;
ans[0][i]=1;
}
for(j=0;j<unit[M];j++)
{
for(i=0;i<unit[M];i++)
{
if(check(i,j,M))
c[i][j]=1;
}
}
/*N=N.subtract(BigInteger.ONE);
for(i=N.bitLength()-1;i>=0;--i){//orz watashi~ learn from shi ge
matrix_mul(unit[M],s,s,P);
if(N.testBit(i)){
matrix_mul(unit[M],s,c,P);
}
}*/
matrix_binary_exp(unit[M], c, N.subtract(BigInteger.ONE), P);
matrix_mul(unit[M], ans, c, P);
//matrix_mul(unit[M], ans, s, P);
long res=0;
for(i=0;i<unit[M];i++)
res=(res+ans[0][i])%P;
System.out.println(res);
if(re>0)
System.out.println();
}
}
public static boolean check(int x,int y,int M){
for(int i=0;i<M-1;i++)
{
if((unit[i]&x)>0&&(unit[i+1]&x)>0&&(unit[i]&y)>0&&(unit[i+1]&y)>0)
return false;
if((unit[i]&x)==0&&(unit[i+1]&x)==0&&(unit[i]&y)==0&&(unit[i+1]&y)==0)
return false;
}
return true;
}
public static void matrix_mul(int n, long x[][], long y[][], int MOD) {
int i, j, k;
long tmp[][]=new long[n][n];
for(i=0;i<n;i++)
for(j=0;j<n;j++)
tmp[i][j]=0;
for (i=0; i<n; ++i) for (j=0; j<n; ++j) for (k=0; k<n; ++k) {
tmp[i][j] = (tmp[i][j] + x[i][k] * y[k][j]);
}
for (i=0; i<n; ++i) for (j=0; j<n; ++j) x[i][j] = tmp[i][j]%MOD;
}
public static void matrix_binary_exp(int n, long x[][], BigInteger exp, int MOD) {
int i, j, k;
long tmp[][]=new long [n][n];
for(i=0;i<n;i++)
for(j=0;j<n;j++)
tmp[i][j]=0;
for (i=0; i<n; ++i) tmp[i][i] = 1;
while (!exp.equals(BigInteger.ZERO)) {
if (exp.mod(BigInteger.valueOf(2)).equals(BigInteger.ONE)) matrix_mul(n, tmp, x, MOD);
matrix_mul(n, x, x, MOD);
exp=exp.divide(BigInteger.valueOf(2));
}
for (i=0; i<n; ++i) for (j=0; j<n; ++j) x[i][j] = tmp[i][j];
}
}
}}}
给N*M的格子,N非常大,M小于等于5,然后对格子黑白染色,使得任意一个2*2的区域的4个格子颜色不能完全相同,问总的方案数
很明显是矩阵乘法,dp[mask]来表示当前行,黑白染色状态是mask的情况下,有多少种方案,这个方案只与上一行的mask有关
然后逐一check两种mask之间是否合法,建立转移矩阵即可
然后此题的N是10^100
于是我用了JAVA来写蛋疼的大数。。非常蛋疼。。而且时限卡的很紧,优化不好就超时,模板我依然用的是好基友、前队友delta的矩阵乘法模板,在JAVA下面改了一下语法格式,也算练练手吧
另外此题中矩阵乘法尽量少用mod,我是参照shi哥的做法,最后才mod的,因为题中mod最大值为10000,所以用long就可以避免爆掉
shi哥的矩阵求幂写法也值得学习,代码中有注释
import java.util.*;
import java.math.*;
public class Main {
static int unit[]={1,2,4,8,16,32,64};
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
BigInteger N;
int M,P,i,j,k;
long c[][]=new long[32][32];
long ans[][]=new long[32][32];
long s[][]=new long[32][32];
int re=in.nextInt();
while(re>0){
re--;
N=in.nextBigInteger();
M=in.nextInt();
P=in.nextInt();
for(i=0;i<32;i++)
for(j=0;j<32;j++)
s[i][j]=c[i][j]=ans[i][j]=0;
for(i=0;i<unit[M];i++)
{
s[i][i]=1;
ans[0][i]=1;
}
for(j=0;j<unit[M];j++)
{
for(i=0;i<unit[M];i++)
{
if(check(i,j,M))
c[i][j]=1;
}
}
/*N=N.subtract(BigInteger.ONE);
for(i=N.bitLength()-1;i>=0;--i){//orz watashi~ learn from shi ge
matrix_mul(unit[M],s,s,P);
if(N.testBit(i)){
matrix_mul(unit[M],s,c,P);
}
}*/
matrix_binary_exp(unit[M], c, N.subtract(BigInteger.ONE), P);
matrix_mul(unit[M], ans, c, P);
//matrix_mul(unit[M], ans, s, P);
long res=0;
for(i=0;i<unit[M];i++)
res=(res+ans[0][i])%P;
System.out.println(res);
if(re>0)
System.out.println();
}
}
public static boolean check(int x,int y,int M){
for(int i=0;i<M-1;i++)
{
if((unit[i]&x)>0&&(unit[i+1]&x)>0&&(unit[i]&y)>0&&(unit[i+1]&y)>0)
return false;
if((unit[i]&x)==0&&(unit[i+1]&x)==0&&(unit[i]&y)==0&&(unit[i+1]&y)==0)
return false;
}
return true;
}
public static void matrix_mul(int n, long x[][], long y[][], int MOD) {
int i, j, k;
long tmp[][]=new long[n][n];
for(i=0;i<n;i++)
for(j=0;j<n;j++)
tmp[i][j]=0;
for (i=0; i<n; ++i) for (j=0; j<n; ++j) for (k=0; k<n; ++k) {
tmp[i][j] = (tmp[i][j] + x[i][k] * y[k][j]);
}
for (i=0; i<n; ++i) for (j=0; j<n; ++j) x[i][j] = tmp[i][j]%MOD;
}
public static void matrix_binary_exp(int n, long x[][], BigInteger exp, int MOD) {
int i, j, k;
long tmp[][]=new long [n][n];
for(i=0;i<n;i++)
for(j=0;j<n;j++)
tmp[i][j]=0;
for (i=0; i<n; ++i) tmp[i][i] = 1;
while (!exp.equals(BigInteger.ZERO)) {
if (exp.mod(BigInteger.valueOf(2)).equals(BigInteger.ONE)) matrix_mul(n, tmp, x, MOD);
matrix_mul(n, x, x, MOD);
exp=exp.divide(BigInteger.valueOf(2));
}
for (i=0; i<n; ++i) for (j=0; j<n; ++j) x[i][j] = tmp[i][j];
}
}