题意:有一排砖,可以染红蓝绿黄四种不同的颜色,要求红和绿两种颜色砖的个数都是偶数,问一共有多少种方案,结果对10007取余。
题解:刚看这道题第一感觉是组合数学,正向推了一会还没等推出来队友就打表找到公式了,然后我就写了一个快速幂加个费马小定理就过了去看别的题了,赛后找到了一个很不错的博客:传送门,原来这道题也可以用DP+矩阵快速幂AC。下面说下组合数学的做法:
首先一共有4^n种情况,我们减去不符合条件的情况就行了,从中取k个进行染红绿色一共C(n,k)种情况,剩下的蓝黄色一共有2^(n-k)种情况,接下来对k的奇偶进行分类讨论。(借用下博客里的公式)
如果k为奇数,红色和绿色的数量为一奇一偶:2 * (c(k, 1) + c(k, 3) + c(k, 5) +……)* c(n, k) * 2^(n - k) (其中要乘以2,是因为可以分别选择红、绿色为奇数)
如果k为偶数,红色和绿色的数量全部为奇数:(c(k, 1) + c(k, 3) + c(k, 5) +……)* c(n, k) * 2^(n - k) (这里不需要乘以2)
而 c(k, 1) + c(k, 3) + c(k, 5) +…… = 2^(k - 1)
所以,最后的表达式为:
4^n - 2^n*c(n, 1) - 2^(n - 1)*c(n, 2) - 2^n*c(n, 3) - 2^(n-1)*c(n, 4)-……
= 4^n - 2^n*2^(n-1) - 2^(n-1)*(2^(n-1)-1)
= 4^(n-1) + 2^(n-1)
在计算过程中我们发现k奇数的时候没有问题是 2*2^(n-1)*2^(n-1)
k偶数的时候要把k=0的情况算上所以要减去一个1,因为k=0是符合情况的不需要减去,这样就没问题了。
另外这题不用费马小定理也能AC。
#include <cstdio> using namespace std; typedef long long ll; const ll mod=10007; ll n; ll pow1(ll a,ll b) { ll ans=1; while(b) { if(b&1) ans=ans*a%mod; b>>=1; a=a*a%mod; } return ans; } int main() { int t; scanf("%d",&t); while(t--) { scanf("%lld",&n); n%=(mod-1); if(n==0) n=mod-1; ll ans=pow1(2,n-1); ans=(ans*ans%mod+ans)%mod; printf("%lld ",ans); } return 0; }