题目链接
我们可以把棱柱拆成有\(n\)条高的矩形,尝试递推。
在计算的过程中,第\(i\)列(\(i\neq n\))只与\(i-1\)列有关,称\(i-1\)列的上面/下面为左上/左下,第\(i\)列的上面/下面为右上/右下。
我们可以发现,右上可选的颜色数与左上和右下是否同色有关,右下同理,那就记\(f[i][0/1][0/1]\)表示左上与右下是否同色,左下与右上是否同色。
但是第\(n\)列和第\(1\)列不能同色,最后怎么算答案?
不知道第\(n\)列状态算不了,所以我们还要记第\(i\)列的上/下是否与第\(1\)列的上&下同色。称\(1\)列的上面/下面为左上/左下,我们发现这样只记与第\(1\)列的情况就可以知道第\(i-1\)列怎么转移到第i列了(这谁发现了。。)。
那么 \(f[i][0/1/2][0/1/2]\) 表示到第\(i\)列,右上的颜色 与左上、左下都不相同/与左上相同/与左下相同;右下的颜色 与左上、左下都不相同/与左上相同/与左下相同 的方案数。
最后的答案就是\(\sum f[n][j\neq 1][k\neq 2]\)(就是\(f[n+1][1][2]\))。可以递推啦。
改成矩阵快速幂就可以AC了。这个矩阵还算好推。
有两组状态是对称的,可以把状态压成5*5?不过没什么用。
转移好恶心啊。
65分递推:
#include
#include
#define mod (1000000007)
typedef long long LL;
const int N=1e6+5;
LL n,m,f[N][3][3];
inline LL FP(LL x,LL k)
{
LL t=1; //x%=mod;
for(; k; k>>=1,x=x*x%mod)
if(k&1) t=t*x%mod;
return t;
}
int main()
{
freopen("planar.in","r",stdin);
freopen("planar.out","w",stdout);
scanf("%lld%lld",&n,&m);
if(m==2) return putchar(n&1?'0':'2'),0;
f[1][1][2]=m*(m-1)%mod;
LL m3=(m-3)*(m-3)%mod, m2=(m-2)*(m-2)%mod, m23=(m-2)*(m-3)%mod, m34=(m3-m+4+mod)%mod;
for(int i=2; i<=n; ++i)
{//LONG_LONG_MAX=9e18 > 4e9*1e9
// LL (*pre)[3]=f[i-1];//慢了smg
f[i][0][0]=(f[i-1][0][0]*m34%mod+
(f[i-1][0][1]+f[i-1][0][2]+f[i-1][1][0]+f[i-1][2][0])*m3%mod+
(f[i-1][1][2]+f[i-1][2][1])*m23%mod)%mod;
f[i][0][1]=((f[i-1][0][0]+f[i-1][0][2])*(m-3)%mod+
(f[i-1][1][0]+f[i-1][2][0]+f[i-1][1][2])*(m-2)%mod)%mod;
f[i][1][0]=((f[i-1][0][0]+f[i-1][2][0])*(m-3)%mod+
(f[i-1][0][1]+f[i-1][0][2]+f[i-1][2][1])*(m-2)%mod)%mod;
f[i][0][2]=((f[i-1][0][0]+f[i-1][0][1])*(m-3)%mod+
(f[i-1][1][0]+f[i-1][2][0]+f[i-1][2][1])*(m-2)%mod)%mod;
f[i][2][0]=((f[i-1][0][0]+f[i-1][1][0])*(m-3)%mod+
(f[i-1][0][1]+f[i-1][0][2]+f[i-1][1][2])*(m-2)%mod)%mod;
f[i][1][2]=(f[i-1][0][0]+f[i-1][0][1]+f[i-1][2][0]+f[i-1][2][1])%mod;
f[i][2][1]=(f[i-1][0][0]+f[i-1][0][2]+f[i-1][1][0]+f[i-1][1][2])%mod;
}
printf("%lld\n",(f[n][0][0]+f[n][0][1]+f[n][2][0]+f[n][2][1])%mod);
return 0;
}
100 矩阵快速幂:
//O(49)推矩阵好恶心啊。
#include
#include
#define mod (1000000007)
typedef long long LL;
const int N=1e6+5;
struct Matrix
{
LL a[7][7];
Matrix operator *(const Matrix &x)
{
Matrix res;
for(int i=0; i<7; ++i)
for(int j=0; j<7; ++j)
{
LL tmp=0;
for(int k=0; k<7; ++k)
tmp+=a[i][k]*x.a[k][j]%mod;
res.a[i][j]=tmp%mod;
}
return res;
}
}A;
inline Matrix FP(Matrix x,LL k)
{
Matrix t=x;
for(--k; k; k>>=1,x=x*x)
if(k&1) t=t*x;
return t;
}
int main()
{//[(7*7)^n]*(7*1) 正好转移n次得到f[n+1]。
freopen("planar.in","r",stdin);
freopen("planar.out","w",stdout);
LL n,m; scanf("%lld%lld",&n,&m);
if(m==2) return putchar(n&1?'0':'2'),0;
/*
0: (0,0)
1: (0,1)
2: (0,2)
3: (1,0)
4: (1,2)
5: (2,0)
6: (2,1)
*/
if(m>=4) A.a[0][0]=((m-3)*(m-3)%mod-(m-4)+mod)%mod;
A.a[0][1]=A.a[0][2]=A.a[0][3]=A.a[0][5]=(m-3)*(m-3)%mod;
A.a[0][4]=A.a[0][6]=(m-2)*(m-3)%mod;
A.a[1][0]=A.a[1][2]=A.a[2][0]=A.a[2][1]=A.a[3][0]=A.a[3][5]=A.a[5][0]=A.a[5][3]=m-3;
A.a[1][3]=A.a[1][4]=A.a[1][5]=A.a[2][3]=A.a[2][5]=A.a[2][6]=A.a[3][1]=A.a[3][2]=A.a[3][6]=A.a[5][1]=A.a[5][2]=A.a[5][4]=m-2;
A.a[4][0]=A.a[4][1]=A.a[4][5]=A.a[4][6]=A.a[6][0]=A.a[6][2]=A.a[6][3]=A.a[6][4]=1;
A=FP(A,n);
printf("%lld\n",A.a[4][4]*m%mod*(m-1)%mod);//f[n+1][1][2] = (A^n)[4][j] * Mat={0,0,0,0,m(m-1),0,0}
// f[1][1][2]=m*(m-1)%mod;
// LL m3=(m-3)*(m-3)%mod, m2=(m-2)*(m-2)%mod, m23=(m-2)*(m-3)%mod, m34=(m3-m+4+mod)%mod;
// for(int i=2; i<=n; ++i)
// {//LONG_LONG_MAX=9e18 > 4e9*1e9
// f[i][0][0]=(f[i-1][0][0]*m34%mod+
// (f[i-1][0][1]+f[i-1][0][2]+f[i-1][1][0]+f[i-1][2][0])*m3%mod+
// (f[i-1][1][2]+f[i-1][2][1])*m23%mod)%mod;
//
// f[i][0][1]=((f[i-1][0][0]+f[i-1][0][2])*(m-3)%mod+
// (f[i-1][1][0]+f[i-1][2][0]+f[i-1][1][2])*(m-2)%mod)%mod;
// f[i][1][0]=((f[i-1][0][0]+f[i-1][2][0])*(m-3)%mod+
// (f[i-1][0][1]+f[i-1][0][2]+f[i-1][2][1])*(m-2)%mod)%mod;
//
// f[i][0][2]=((f[i-1][0][0]+f[i-1][0][1])*(m-3)%mod+
// (f[i-1][1][0]+f[i-1][2][0]+f[i-1][2][1])*(m-2)%mod)%mod;
// f[i][2][0]=((f[i-1][0][0]+f[i-1][1][0])*(m-3)%mod+
// (f[i-1][0][1]+f[i-1][0][2]+f[i-1][1][2])*(m-2)%mod)%mod;
//
// f[i][1][2]=(f[i-1][0][0]+f[i-1][0][1]+f[i-1][2][0]+f[i-1][2][1])%mod;
// f[i][2][1]=(f[i-1][0][0]+f[i-1][0][2]+f[i-1][1][0]+f[i-1][1][2])%mod;
// }
return 0;
}
25分的考场代码:
//Subtask?
#include