BZOJ 1002: [FJOI2007]轮状病毒

好久好久好久好久没写博客了,由于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< 
        
          < 
          
         
       
      
      
     
     
    
    
   
   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值