zoukankan      html  css  js  c++  java
  • codeforces 425E

    题意:对于[l1, r1], [l2, r2]...[lm, rm]线段组成的一个集合S,我们定义f(S)为最大的不相交(没有任何公共点)线段数,现在给定n及k,n表示线段范围,即任何[li, ri]有1<=li<=ri<=n,求有多少个集合使得f(S) = k。

    思路:刚看到题目感觉不会,也就不多想。。

             突然问了下小胖,小胖说他做过,不难。。然后我就慢慢想了。。

             仔细想想,确实不难。。

              假设现在已经给定了一个S,那么我们怎么求f(S)?

              很显然,我们可以贪心,按照r排序,那么我们每次只要取最小r的线段,删除覆盖的,依次做完最后取到的线段肯定最多。。

              这么以来对于任意一个集合S,我们肯定可以用最小的有用线段的右端点r来表示其状态。。

              所以用f[i][j]表示最后一个有用线段右端点为i,最长有j段不相交的线段的方案数

              则递推到f[k][j+1](k>i)的状态有:

               在【i+1, k】区间内一定选了至少一条以k为右端点的线段,选法2k-i - 1

               左端点在【1, i】右端点【i+1, k】的线段可以任意选不影响f值,有2(k-i)*i

               所以 f[k][j+1] += f[i][j] *(2k-i - 1) * 2(k-i)*i

    code:

     1 #include <bits/stdc++.h>
     2 #define M0(x) memset(x, 0, sizeof(x))
     3 #define M 1000000007
     4 using namespace std;
     5 typedef long long ll;
     6 const int maxn = 512;
     7 int n, m;
     8 ll dp[512][512], p[300000];
     9 
    10 void solve(){
    11      if (m == 0){
    12          puts("1");
    13          return;
    14      }
    15      M0(dp);
    16      dp[0][0] = 1;
    17      p[0] = 1;
    18      for (int i = 1; i <= n * n; ++i) p[i] = (p[i-1] << 1) % M;
    19      ll tmp;
    20      int c = 0;
    21      for (int i = 0; i < n; ++i)
    22          for (int j = 0; j < m; ++j) if (dp[i][j]){
    23               c = 0;
    24               for (int k = i+1; k <= n; ++k){
    25                     c += i;
    26                     tmp = dp[i][j] * (p[(k - i)]-1) % M * p[c] % M;
    27                     dp[k][j+1] = (dp[k][j+1] + tmp) % M;
    28               }
    29          }
    30      ll ans = 0;
    31      for (int i = 1; i <= n; ++i){
    32            tmp = p[(n-i) * i] * dp[i][m] % M;
    33            ans = (ans + tmp) % M; 
    34 //           printf("%d : %lld
    ",i,  ans);
    35      }
    36      cout << ans << endl;
    37 }
    38 
    39 int main(){
    40     freopen("a.in", "r", stdin);
    41     while (scanf("%d%d", &n, &m) != EOF){
    42          solve();
    43     }
    44     return 0;
    45 }
    View Code
  • 相关阅读:
    发布spring cloud + vue项目
    以太坊上发行ERC20代币
    [转]大白话讲解Promise(一)
    比特币测试网络搭建
    非对称加密, 助记词, PIN, WIF
    搭建EOS未完
    [转]EOS智能合约 & 私链激活 & 基本操作
    [转]https://www.jianshu.com/p/06443248f4d8
    web3js 进行转账
    [转]How to Send Ethereum with Web3.js and Node
  • 原文地址:https://www.cnblogs.com/yzcstc/p/4065898.html
Copyright © 2011-2022 走看看