题意:求 f(n) = f(n-1) + 2*f(n - 2) + n^4
思路:太部分人都知道举证快速幂,但是不知道如何凑矩阵
。。。这个我想了快两个小时才想出来。。。太菜了。
[ f ( n ) f ( n − 1 ) ( n + 1 ) 4 ( n + 1 ) 3 ( n + 1 ) 2 ( n + 1 ) 1 ] (A) \left[ \begin{matrix} f(n) \\ f(n-1) \\ (n + 1)^4 \\ (n + 1)^3 \\ (n + 1)^2 \\ (n + 1) \\ 1 \end{matrix} \right] \tag{A} ⎣⎢⎢⎢⎢⎢⎢⎢⎢⎡f(n)f(n−1)(n+1)4(n+1)3(n+1)2(n+1)1⎦⎥⎥⎥⎥⎥⎥⎥⎥⎤(A)
[
1
2
1
0
0
0
0
1
0
0
0
0
0
0
0
0
1
4
6
4
1
0
0
0
1
3
3
1
0
0
0
0
1
2
1
0
0
0
0
0
1
1
0
0
0
0
0
0
1
]
(B)
\left[ \begin{matrix} 1 & 2 & 1 & 0 & 0 & 0 & 0 & \\ 1 & 0 & 0 & 0 & 0 & 0 & 0 & \\ 0 & 0 & 1 & 4 & 6 & 4 & 1 & \\ 0 & 0 & 0 & 1 & 3 & 3 & 1 & \\ 0 & 0 & 0 & 0 & 1 & 2 & 1 & \\ 0 & 0 & 0 & 0 & 0 & 1 & 1 & \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & \\ \end{matrix} \right] \tag{B}
⎣⎢⎢⎢⎢⎢⎢⎢⎢⎡1100000200000010100000041000006310000432100011111⎦⎥⎥⎥⎥⎥⎥⎥⎥⎤(B)
[
f
(
n
−
1
)
f
(
n
−
2
)
n
4
n
3
n
2
n
1
]
(C)
\left[ \begin{matrix} f(n - 1) \\ f(n-2) \\ n ^4 \\ n ^3 \\ n ^2 \\ n \\ 1 \\ \end{matrix} \right] \tag{C}
⎣⎢⎢⎢⎢⎢⎢⎢⎢⎡f(n−1)f(n−2)n4n3n2n1⎦⎥⎥⎥⎥⎥⎥⎥⎥⎤(C)
有了这三个矩阵就可以得到
A = B * C
[
f
(
2
)
f
(
1
)
81
27
9
3
1
]
(D)
\left[ \begin{matrix} f(2) \\ f(1) \\ 81 \\ 27\\ 9 \\ 3 \\ 1 \\ \end{matrix} \right] \tag{D}
⎣⎢⎢⎢⎢⎢⎢⎢⎢⎡f(2)f(1)8127931⎦⎥⎥⎥⎥⎥⎥⎥⎥⎤(D)
便可以推导出 :
A = (C ^ n - 2 ) * D
然后就是简单的矩阵快速幂了
#include<iostream>
using namespace std;
typedef long long ll;
ll n;
ll mod = 2147493647;
struct matrix{
ll mp[7][7];
matrix(){
for(int i = 0; i < 7; i++){
for(int j = 0; j < 7; j++){
mp[i][j] = 0;
}
}
}
};
matrix mul(matrix a, matrix b){
matrix ans;
for(int i = 0; i < 7; i++){
for(int j = 0; j < 7; j++){
for(int k = 0; k < 7; k++){
ans.mp[i][j] = (ans.mp[i][j] + (a.mp[i][k] % mod * b.mp[k][j] % mod) % mod) % mod;
}
}
}
return ans;
}
matrix ksm(matrix cnt, ll n){
matrix base;
for(int i =0; i < 7; i++){
base.mp[i][i] = 1;
}
while(n){
if(n & 1){
base = mul(base, cnt);
}
cnt = mul(cnt, cnt);
n = n / 2;
}
return base;
}
int main(){
ll x, y;
int t; scanf("%d", &t);
while(t--){
scanf("%lld%lld%lld", &n, &x, &y);
x = x % mod;
y = y % mod;
if(n == 1){
printf("%lld\n", x);
continue;
}
if(n == 2){
printf("%lld\n", y);
continue;
}
matrix ans;
ans.mp[0][0] = 1, ans.mp[0][1] = 2, ans.mp[0][2] = 1;
ans.mp[1][0] = 1, ans.mp[2][2] = 1, ans.mp[2][3] = 4;
ans.mp[2][4] = 6, ans.mp[2][5] = 4, ans.mp[2][6] = 1;
ans.mp[3][3] = 1, ans.mp[3][4] = 3, ans.mp[3][5] = 3;
ans.mp[3][6] = 1, ans.mp[4][4] = 1, ans.mp[4][5] = 2;
ans.mp[4][6] = 1, ans.mp[5][5] = 1, ans.mp[5][6] = 1;
ans.mp[6][6] = 1;
ans = ksm(ans, n - 2);
matrix res;
res.mp[0][0] = y;
res.mp[1][0] = x;
res.mp[2][0] = 81;
res.mp[3][0] = 27;
res.mp[4][0] = 9;
res.mp[5][0] = 3;
res.mp[6][0] = 1;
res = mul(ans, res);
printf("%lld\n", res.mp[0][0] % mod);
}
}
HDU - 5952
题意:让你找出所有大小为s的团,其中团指:任意两点都有边。
思路:这题数据比较小可以暴力。。。
但是,暴力也要好好写不然就和我一样一直 TL。。
我刚开时的思路就是找每个节点 连接的点数 大于 s - 1的,
然后 在链接的点中dfs 枚举 所有 的 s-1 的组合在判断是否满足
复杂度 应该为 0(n3 * 2 ^ 20 )因为我判断 是否满足就要花 n^2的时间
看来别人的思路,可以先判断在找。
同样 也是找每个节点 连接的点数 大于 s - 1的,然后 用 vector < int >v记录 与该点可以构成团的点 ,我们没dfs一个点时,只有判断 v里面所有点与该点是否链接
颜色全部连接,就选这个点 知道 v的个数为 s为止。
难点:双向建边会导致重复的计算 我只有建一条边就ok了统一按照节点数小的连接大的就行了。
#include<bits/stdc++.h>
using namespace std;
const int N = 107;
int t, n, m, s, vis[N][N];
vector<int> g[N];
vector<int> v;
int ans = 0;
void dfs(int u, int p){
if(p == s){
ans++;
return;
}
for(int i: g[u]){
int f = 0;
for(int j: v){
if(!vis[min(i, j)][max(i, j)]){
f = 1;
break;
}
}
if(!f){
v.push_back(i);
dfs(i, p + 1);
v.pop_back();
}
}
}
int main(){
scanf("%d", &t);
while(t--){
ans = 0;
scanf("%d %d %d", &n, &m, &s);
for(int i = 1; i <= m; i++){
int u, v;
scanf("%d %d", &u, &v);
vis[min(u, v)][max(u, v)] = 1;
g[min(u, v)].push_back(max(u, v));
}
for(int i = 1; i <= n; i++){
if(g[i].size() + 1 >= s){
v.push_back(i);
dfs(i, 1);
v.pop_back();
}
}
printf("%d\n", ans);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
vis[i][j] = 0;
}
g[i].clear();
}
}
}