HDU - 5950 and HDU - 5952

HDU - 5950

题意:求 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(n1)n+14(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(n1)f(n2)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();
        }
   }
   
   
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值