https://www.hackerrank.com/challenges/lego-blocks/editorial
解法真的很impressive,横着要考虑,竖直的角度也要考虑。
先考虑简单的情况:没有第二个限制,每层就是独立的,对于一层用DP求出n情况下的可能数,然后快速幂得到n层的可能数。
现在加上第二个限制,一个思路就是从随便放的所有情况减去违反第二个限制的情况数。现在就focus在求违反第二个现在的总数。
很明显,需要循环枚举一下不满足的列是第几列,然后该列把M列分成了2部分,2部分不能是随便放的,这样会有重复。应该是一边放不违反第二个限制的,一边随便放,这样可以避免重复计算。假设左边是不违反第二个限制的,那此时枚举的第几列,就代表:第一次出现违反限制的列数
mod=10**9+7
f=[1]*(1001)
f[1],f[2],f[3]=1,2,4
for i in range(4,1001):
f[i]=(f[i-1]+f[i-2]+f[i-3]+f[i-4])%mod
def power(a,b):
res,base=1,a
while b:
if b&1:
res*=base
res%=mod
base*=base
base%=mod
b=b//2
return res
def legoBlocks(n, m):
p=[0]*(m+1)
for i in range(1,m+1): p[i]=power(f[i],n)
res=[1]*(m+1)
for i in range(2,m+1):
res[i]=p[i]
for j in range(1,i):
res[i]-=res[j]*p[i-j]
res[i]=(res[i]+mod)%mod
return res[m]
print(legoBlocks(2, 2))
print(legoBlocks(3, 2))
print(legoBlocks(2, 3))
print(legoBlocks(4, 4))
Java要注意数据溢出,先求mod,然后再check一遍,因为在Python里面负数取余会自动变成整数,比如-5%3=1
import java.io.IOException;
import java.util.Arrays;
import java.util.Scanner;
public class Solution {
public static int mod=1000000007, max=1000;
public static long[]f;
/*
* Complete the legoBlocks function below.
*/
public static int legoBlocks(int n, int m) {
/*
* Write your code here.
*/
return (int) solve(n,m);
}
public static long solve(int n, int m) {
long[] p=new long[m+1];
for(int i=1;i<=m;i++) p[i]=power(f[i],n);
long[] res=new long[m+1];
Arrays.fill(res, 1);
for(int i=2;i<=m;i++) {
res[i]=p[i];
for(int j=1;j<i;j++) {
res[i]-=res[j]*p[i-j];
res[i]%=mod;
res[i]=(res[i]+mod)%mod;
if(res[i]<0) System.out.println("error");
}
}
return res[m];
}
public static long power(long a,long b) {
long res=1,base=a;
while(b!=0) {
if((b&1)!=0) {
res*=base;
res%=mod;
}
base*=base;
base%=mod;
b=b/2;
}
return res;
}
private static final Scanner scanner = new Scanner(System.in);
public static void main(String[] args) throws IOException {
f=new long[max+1];
Arrays.fill(f, 1);
f[2]=2;
f[3]=4;
for(int i=4;i<=max;i++) f[i]=(f[i-1]+f[i-2]+f[i-3]+f[i-4])%mod;
int t = Integer.parseInt(scanner.nextLine().trim());
for (int tItr = 0; tItr < t; tItr++) {
String[] nm = scanner.nextLine().split(" ");
int n = Integer.parseInt(nm[0].trim());
int m = Integer.parseInt(nm[1].trim());
int result = legoBlocks(n, m);
System.out.println(result);
}
}
}