BZOJ 1002: [FJOI2007]轮状病毒

本文介绍了一道关于计算不同轮状病毒数量的问题。通过构建最小生成树模型,使用动态规划的方法来解决这一问题。文章详细阐述了状态定义、状态转移方程及实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

好久好久好久好久没写博客了,由于csdn改版了,一直不大喜欢,所以也就不大乐意上博客了。。其实说起来也没什么题好写的,有时候还是会做到好题的,由于已经忘记了csdn忘记了我有博客,于是就没写了。but 现在还是继续开始吧,有什么感觉不错的题还是可以mark下的。


接下来是题意,中文题就是好,直接上题目。。

 给定n(N<=100),编程计算有多少个不同的n轮状病毒。


思路:

题目就是求最小生成树的种数,中心的点必须要和周围的一圈点连通,可以先不要管环,先考虑链的情况

dp[ i ][ 0 ]表示第i个点还没和中心点连通,并且前i-1个点和中心点或者第i个点是连通的

dp[ i ][ 1 ]表示前i个点全部都已经和中心点连通了

很容易可以推出状态转移方程 :

dp[ i ][ 0 ] = dp[ i-1 ][ 0 ] + dp[ i-1 ][ 1 ]

dp[ i ][ 1 ] = dp[ i-1 ][ 0 ] + dp[ i-1 ][ 1 ]*2

那么对于n轮状病毒,可以枚举第一个点和多少个周围的点连通,其余的点就是一条链的情况了。



ps: 高精度是必须的


code:

#include 
#include 
#include 
#include 
#include 
using namespace std;
 
const int numlen = 205;
 
struct bign {
    int len, s[numlen];
    bign(){
        memset(s, 0, sizeof(s));
        len = 1;
    }
    bign(int num) { *this = num; }
    bign(const char *num) { *this = num; }
    bign operator = (const int num) {
        char s[numlen];
        sprintf(s, "%d", num);
        *this = s;
        return *this;
    }
    bign operator = (const char *num) {
        len = strlen(num);
        while(len > 1 && num[0] == '0') num++, len--;
        for(int i = 0;i < len; i++) s[i] = num[len-i-1] - '0';
        return *this;
    }
    void deal() {
        while(len > 1 && !s[len-1]) len--;
    }
    bign operator + (const bign &a)const {
        bign ret ;
        ret.len = 0;
        int top = max(len, a.len), add = 0;
        for(int i = 0;add || i < top; i++) {
            int now = add;
            if(i < len) now += s[i];
            if(i < a.len)   now += a.s[i];
            ret.s[ret.len++] = now%10;
            add = now/10;
        }
        return ret;
    }
    bign operator *(const int num) const {
        bign ret;
        ret.len = 0;
        int bb = 0;
        for(int i = 0;i < len; i++) {
            int now = bb + s[i]*num;
            ret.s[ret.len++] = now%10;
            bb = now/10;
        }
        while(bb) {
            ret.s[ret.len++] = bb%10;
            bb /= 10;
        }
        ret.deal();
        return ret;
    }
    string str() const {
        string ret = "";
        for(int i = 0;i < len; i++) ret = char(s[i]+'0') + ret;
        return ret;
    }
};
istream& operator >> (istream &in, bign &x) {
    string s;
    in >> s;
    x = s.c_str();
    return in;
}
ostream& operator << (ostream &out, const bign &x) {
    out << x.str();
    return out;
}
 
const int N = 100+5;
 
bign dp[N][2], ans[N];
 
void init(int n) {
    dp[0][1] = 1;
    dp[1][1] = dp[1][0] = 1;    // 0: 表示未连接好的  1: 表示为连接好的
    for(int i = 2;i <= n; i++) {
        dp[i][1] = dp[i-1][0] + dp[i-1][1]*2;
        dp[i][0] = dp[i-1][0] + dp[i-1][1];
    }
    for(int i = 1;i <= n; i++) {
        ans[i] = 0;
        for(int j = 1;j <= i; j++) {
            ans[i] = ans[i] + dp[i-j][1]*j*j;
        }
    }
}
 
int main(){
    int n;
    scanf("%d", &n);
    init(n);
    cout<

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值