SRM 584 DIV1

A

  简单的差分约束模型 , 因为d是定值 , 所以也可以按最短路理解 , trick是不能把圈算进去.

  

 1 #define maxn 55

 2 class Egalitarianism {

 3 public:

 4     int maxDifference(vector <string>, int);

 5 };

 6 int e[maxn][maxn],n,f[maxn][maxn];

 7 int Egalitarianism::maxDifference(vector <string> isFriend, int d) {

 8     n = isFriend.size();

 9     memset(e,-1,sizeof(e));

10     for (int i=0 ; i<n ; i++ ) {

11         for (int j=0 ; j<n ; j++ ) if (isFriend[i][j]=='Y') {

12             e[i][j] = d;

13         }

14     }

15     int ans = -1;

16     for (int k=0 ; k<n ; k++ ) {

17         for (int i=0 ; i<n ; i++ ) {

18             for (int j=0 ; j<n ; j++ ) if (e[i][k] != -1 && e[k][j] != -1) {

19                 if (e[i][j]==-1 || e[i][j]>e[i][k] + e[k][j])

20                     e[i][j] = e[i][k]+e[k][j];

21             }

22         }

23     }

24     for (int i=0 ; i<n ; i++ ) for (int j=0 ; j<n ; j++ )  if (i!=j){

25         if (e[i][j] == -1) return -1;

26         ans = max(ans,e[i][j]);

27     }

28     return ans;

29 }
View Code

 

B

  计数模型很好想 , 但是有很多细节要想清楚 , 一开始想简单了......

  离散化之后 , dp[i][j][k] 表示满足要求的方案数:

  (1) 挖了前i种东西;

  (2) 所以挖出来的东西最大深度为j;

  (3) 挖出来了k个;

  (4) 每个都是在found里出现的;

  然后 ans = sigma ( dp[51][j][k] * factor[j][k] ) (1<=j<INF , found.size()<=j<=K);

  比较麻烦的地方在对于给定的状态 , 计算对应factor:

  (1)  还要挖 K-k个 , 并且他们的深度大于j , 即不能被发现;

  (2)  要把所有的building考虑进去,而不仅仅是不在found里面的;

  (3)  必须保证接下来挖的中,深度最小的building未在found里出现 , 否则会重复计数;

  

  1 using namespace std;

  2 #define maxn 60

  3 #define maxd 100010

  4 #include <cstring>

  5 const int INF = maxd-1;

  6 typedef long long llong;

  7 

  8 class Excavations {

  9 public:

 10     long long count(vector <int>, vector <int>, vector <int>, int);

 11 };

 12 

 13 bool in[maxn];

 14 llong c[maxn][maxn] , b[maxn][maxn][maxn] ;//, s[maxn][maxn][maxn] , s2[maxn][maxn][maxn];

 15 int cnt[maxn],n,m,D;

 16 map<int,int> hk , hd;

 17 vector<int> bufk , bufd , t[maxn];

 18 

 19 struct node{

 20     int k,d;

 21 };node build[maxn];

 22 

 23 bool cmp (node a , node b) {

 24     if (a.k == b.k) return a.d<b.d;

 25     return a.k<b.k;

 26 }

 27 void pretreat(vector<int> kind,vector<int> depth,vector<int> found) {

 28     n = kind.size();

 29     m = found.size();

 30     bufd.push_back(0);

 31     bufd.push_back(INF);

 32     bufk.push_back(0);

 33     for (int i=0 ; i<n ; i++ ) bufk.push_back(kind[i]) , bufd.push_back(depth[i]);

 34     sort(bufd.begin(),bufd.end());

 35     sort(bufk.begin(),bufk.end());

 36     bufd.erase( unique(bufd.begin(),bufd.end()) , bufd.end() ) ;

 37     bufk.erase( unique(bufk.begin(),bufk.end()) , bufk.end() ) ;

 38     for (int i=0 ; i<(int)bufk.size() ; i++ ) hk[bufk[i]] = i;

 39     for (int i=0 ; i<(int)bufd.size()  ; i++ ) hd[bufd[i]] = i;

 40     for (int i=0 ; i<n ; i++ ) build[i] = (node){hk[kind[i]] , hd[depth[i]]};

 41     sort(build,build+n,cmp);

 42     for (int i=0 ; i<m ; i++ )    in[hk[found[i]]] = 1;

 43     for (int i=0 ; i<=50 ; i++ ) {

 44         c[i][0] = 1;

 45         for (int j=1 ; j<=i ; j++ ) c[i][j] = c[i-1][j-1] + c[i-1][j];

 46     }

 47     D = hd[maxd-1];

 48     for (int i=0 ; i<=D ; i++ ) {

 49         for (int j=0 ; j<n ; j++ ) if (build[j].d>=i)

 50             cnt[i] ++;

 51     }

 52     for (int i=0 ; i<n ; i++ ) t[build[i].k].push_back(build[i].d);

 53     for (int i=0 ; i<=50 ; i++ ) sort(t[i].begin() , t[i].end());

 54 }

 55 

 56 long long Excavations::count(vector <int> kind, vector <int> depth, vector <int> found, int K) {

 57     pretreat(kind,depth,found);

 58 

 59     b[0][0][0] = 1;

 60     for (int i=0 ; i<51 ; i++ )

 61     for (int j=0 ; j<D ; j++ )

 62     for (int k=0 ; k<=K ; k++ ) if (b[i][j][k]) { //printf("b[%d][%d][%d]=%lld\n",i,j,k,b[i][j][k]);

 63         

 64         int debug = 0;

 65         if (j==11) debug = 1;

 66         

 67         if (in[i+1]) {// printf("t[%d].size()=%d\n",i+1,(int)t[i+1].size()); for (int x=0 ; x<(int)t[i+1].size() ; x++ ) printf("%d ",t[i+1][x]); printf("\n");

 68             for (int x=0 ; x<(int)t[i+1].size() ; x++ )

 69             for (int y=0 ; y<=x ; y++ ) {

 70                 if (y+1+k>K) break;

 71                 int dep = max(j, t[i+1][x]);

 72                 b[i+1][dep][y+1+k] += b[i][j][k] * c[x][y];

 73                 if (debug) {

 74             //        printf("b[%d][%d][%d] add %lld * c[%d][%d](%lld) = %lld\n",i+1,dep,y+1+k,b[i][j][k],x,y,c[x][y],b[i][j][k]*c[x][y]);

 75                 }

 76             }

 77         } else {

 78             b[i+1][j][k] += b[i][j][k];

 79         //    if (debug) printf("b[%d][%d][%d] add %lld\n",i+1,j,k,b[i][j][k]);

 80         }

 81     }

 82     llong ans = 0;

 83 

 84     vector<int> illegal;

 85     int f[maxn];

 86     memset(f,0,sizeof(f));

 87     for (int i=0 ; i<n ; i++ ) if (!in[build[i].k]) {

 88         illegal.push_back(build[i].d);

 89         f[build[i].d] ++ ;

 90     }

 91     sort(illegal.begin(),illegal.end());

 92     illegal.erase( unique(illegal.begin(),illegal.end()) , illegal.end() );

 93 

 94     for (int i=1 ; i<D ; i++ )

 95     for (int j=m ; j<=K ; j++ ) if (b[51][i][j]) {

 96         if (j==K) {

 97             ans += b[51][i][j];

 98             printf("add: b[%d][%d]=%lld\n",i,j,b[51][i][j]);

 99         }

100         else {

101             llong fct = 0;

102             for (int x=0 ; x<(int)illegal.size() ; x++ ) if (illegal[x]>i) {

103                 int d = illegal[x];

104                 int need = K-j;

105                 for (int y=1 ; y<=need && y<=f[d] ; y++ ) {

106                     fct += c[f[d]][y] * c[cnt[d]-f[d]][need-y];

107                     printf("fct add: c[%d][%d] * c[%d][%d] = %lld\n",f[d],y,cnt[d]-f[d],need-y,c[f[d]][y]*c[cnt[d]-f[d]][need-y]);

108                 }

109             }

110             ans += b[51][i][j] * fct;

111         }

112     }

113     return ans;

114 }
View Code

 

 

C

  裸的斯坦纳树。。。字符串处理可以这样写:

 1 string s = "";

 2     for (int i=0 ; i<(int)courseInfo.size() ; i++ ) s += courseInfo[i];

 3     stringstream ss(s);

 4     string t;

 5     while (ss>>t) {

 6         sscanf(t.c_str(),"%c%d->%c%d:%d",&a,&da,&b,&db,&cst);

 7         int pa , pb;

 8         pa = encode((int)(a-'A'),da);

 9         pb = encode((int)(b-'A'),db);

10         addedge(pb,pa,cst);

11     }
View Code

  斯坦纳树有2部分更新:

  (1) 对确定的根v , 用mask的子集更新: dp[v][mask] = min ( dp[v][submask] + dp[v][mask - submask])

  本质上是寻找树最优的组合结构,不会有松弛.

  (2) 对确定的根v , 用点u松弛: dp[v][mask] = min ( dp[v][mask] , dp[u][mask] + 最短路(u,v) )

  

你可能感兴趣的:(div)