SRM 584

250pt:

       给一幅图的每个点都赋值,使得相邻两个点的权值之差不超过d,最后问最大权与最小权之差是多少。

      显然,任意两个点的差距不会超过他们的最短距离 * d。

500pt:

     一个诡异的DP,需要枚举D,然后如果要凸显这个D是上界,必须要至少取一个D+1,而且要在非found类里面,因为D+1肯定不能再found类里面。枚举D后每次用dp统计就好了

    

#include <cstdio>
#include <cstring>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <sstream>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <bitset>
#include <algorithm>
using namespace std;
#define clr(a, x) memset(a, x, sizeof(a))
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define REP(i,a,b) for(int i=a;i<=b;i++)
template <class T> void checkmax(T &t, T x) { if (x > t) t = x; }
template <class T> void checkmin(T &t, T x) { if (x < t) t = x; }
template <class T> void _checkmax(T &t, T x) { if (t == -1 || x > t) t = x; }
template <class T> void _checkmin(T &t, T x) { if (t == -1 || x < t) t = x; }
typedef long long ll;
class Excavations {
    public:
    long long count(vector <int> kind, vector <int> depth, vector <int> found, int K) ;

};
const int N = 55;
ll dp[2][N],C[N][N];;
long long Excavations::count(vector <int> kind, vector <int> depth, vector <int> found, int K)  {
      REP(i,0,50) {
        C[i][0] = 1;
        REP(j,1,i) {
            C[i][j] = C[i-1][j] + C[i-1][j-1];
        }
      }
      //cout<<C[10][10]<<endl;
      int n = kind.size() , m = found.size();
      map<int,int> mp;
      rep(i,n) mp[depth[i]]=0;
      int D=0;
      for(map<int,int>::iterator it = mp.begin(); it!=mp.end(); it++) it->second=D++;
      rep(i,n) depth[i]=mp[depth[i]];
      int cnt[55];
      ll ans = 0;
      rep(d,D) {
         memset(cnt,0,sizeof(cnt));
         int Higher = 0;
         rep(i,n) {
            int k = -1;
            rep(j,m) if(found[j] == kind[i]) k = j;
            if(depth[i] <= d && k !=-1) ++cnt[k];
            else if(depth[i] == d+1 && k == -1) ++cnt[m]; // 非found类而且刚好大于d,来凸显d这个上界
            else  if(depth[i] > d)Higher ++;
         }
       //  rep(i,m+1) cout<<cnt[i]<<" ";
       //  cout<<endl;
         int cur = 0;
         memset(dp[cur],0,sizeof(dp[cur]));
         dp[0][0] = 1;
         //cnt[0~m] 每一种至少选一个
         rep(i,m+1) {
            cur ^= 1;
            memset(dp[cur],0,sizeof(dp[cur]));
            REP(j,1,cnt[i]) {
                REP(k,0,K-j) {
                    dp[cur][k+j] += dp[1-cur][k] * C[cnt[i]][j];
                }
            }
             if(d == D-1 && i == m-1) ans += dp[cur][K];
         }
        // rep(i,K+1) cout<<dp[cur][i]<<" ";
        // cout<<endl;
         REP(i,0,K) ans += dp[cur][i] * C[Higher][K-i];
        // cout<<"high:" <<Higher<<"  "<<ans<<endl;
      }
      return ans;
}

    // BEGIN CUT HERE
int main() {
    Excavations ___test;
    ___test.run_test(-1);
}
    // END CUT HERE

900pt:

    两种做法,一种是用斯坦纳树,一种是用最小树形图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值