个人比赛总结(坑

存题处 

/******************/ 

为了迎接社会主义现代化建设所必须要的技术:

1、尺取法

2、反转法

3、弹性碰撞

4、折半枚举

5、坐标离散化

 

一、动规

1.概率dp

URAL 1776  Anniversary Firework

思路:此题直接求期望太过复杂。因为期望等于所有可能答案的概率与该答案的值的乘积的累加和,所以,我们可以求对于每个可能答案的概率,由此简化问题。

ExpandedBlockStart.gif
 1  #include <cstdio>
 2  #include <algorithm>
 3  #include <vector>
 4  #include <cstring>
 5 
 6  const  int  N =  400  +  10 ;
 7  double  d[N][N], sum[N][N];
 8 
 9  int  main() {
10      int  n;
11      scanf( " %d " , &n);
12      n -=  2 ;
13 
14      memset(d,  0 sizeof  d);
15      memset(sum,  0 sizeof  sum);
16 
17      d[ 0 ][ 0 ] =  1 .;
18      for  ( int  j =  0 ; j <= n; ++j)
19          sum[ 0 ][j] =  1 .;
20 
21      for  ( int  i =  1 ; i <= n; ++i) {
22          for  ( int  j =  0 ; j <= i -  1 ; ++j) {
23              int  l = j, r = i -  1  - j;
24              int  t = std::max(l, r) +  1 ;
25 
26              for  ( int  k =  1 ; k <= t; ++k) {
27                  d[i][k] += (d[l][k -  1 ] * sum[r][k -  1 ] + d[r][k -  1 ] * sum[l][k -  1 ] - d[l][k -  1 ] * d[r][k -  1 ]) / i;
28              }
29 
30              for  ( int  j =  1 ; j <= n; ++j)
31                  sum[i][j] = sum[i][j -  1 ] + d[i][j];
32          }
33      }
34 
35      double  ans =  0 ;
36      for  ( int  j =  1 ; j <= n; ++j)
37          ans = ans + d[n][j] * j *  10 ;
38 
39      printf( " %.8f\n " , ans);
40      return  0 ;
41  }
View Code 

2.树形dp 

CodeForces 208B Solitaire 

题意:n张牌,如果第i张牌与第i-1或者第i-3张牌花色一样或者数字一样,那么可以将这两张牌合并,合并后,第i张牌覆盖合并的牌。

问将n张牌合并成一张牌是否可能。n <=52。 

思路:dp(i,a,b,c)//前i张牌,第i张是c,第i-1张是b,第i-2张是c时是否可以合并成功

 

3.朴素dp

二、图论 

1.最短路

2.网络流

URAL 1774  Barber of the Army of Mages

三、数据结构

1.并查集 

SGU 336 Elections

2.树状数组

UVA 12429  Finding Magic Triplets

题意:对于给定的n和K,要求满足a+b*b=c*c*c(mod K) ——(1<=a<=b<=c<=n)的组合数

方法:我们发现,当我们固定b的时候,左侧是一个连续的区间,我们可以预先将右侧的值存入树状数组,然后询问区间和即可。

要注意把握连续区间这一特点,还有固定中间值这个方法 

ExpandedBlockStart.gif
 1  #include <cstdio>
 2  #include <cstring>
 3  #include <algorithm>
 4  typedef  long  long  ll;
 5  #define  lson l, mid, rt << 1
 6  #define  rson mid + 1, r, rt << 1 | 1
 7  const  int  N =  100000  +  10 ;
 8  int  T =  0 ;
 9 
10  ll sum[N];
11  int  K;
12 
13  void  add( int  pos, ll v) {
14      if  (pos ==  0 ) sum[ 0 ] += v;
15      else  {
16          for  (;pos < K; pos += pos & -pos)
17              sum[pos] += v;
18      }
19  }
20  ll query( int  pos) {
21      if  (pos <  0 return  0 ;
22      else  {
23          ll re = sum[ 0 ];
24          for  (;pos >  0 ; pos -= pos & -pos)
25              re += sum[pos];
26          return  re;
27      }
28  }
29  inline ll Q( int  L,  int  R) {
30      return  query(R) - query(L -  1 );
31  }
32  void  work() {
33      int  n;
34      memset(sum,  0 sizeof (ll) * K);
35      scanf( " %d%d " , &n, &K);
36 
37      int  l, r, v;
38      ll ans =  0 ;
39      for  ( int  b = n; b >=  1 ; --b) {
40          v = (ll)b * b * b % K;
41          add(v,  1 );
42 
43          v = (ll)b * b % K;
44          if  (K > b) {
45              l =  1 ; r = b;
46              l = (l + v) % K; r = (r + v) % K;
47              if  (r < l) {
48                  ans += Q( 0 , r) + Q(l, K -  1 );
49              }  else  {
50                  ans += Q(l, r);
51              }
52          }  else  {
53              l =  0 ; r = K -  1 ;
54              l = (l + v) % K; r = (r + v) % K;
55              if  (r < l) {
56                  ans += Q( 0 , r) * (b / K) + Q(l, K -  1 ) * (b / K);
57              }  else  {
58                  ans += Q(l, r) * (b / K);
59              }
60              if  (b % K >  0 ) {
61                  l =  1 ; r = b % K;
62                  l = (l + v) % K; r = (r + v) % K;
63                  if  (r < l) {
64                      ans += Q( 0 , r) + Q(l, K -  1 );
65                  }  else  {
66                      ans += Q(l, r);
67                  }
68              }
69          }
70      }
71 
72      printf( " Case %d: %lld\n " , ++ T, ans);
73  }
74  int  main() {
75      int  cas;
76      scanf( " %d " , &cas);
77      while  (cas -- >  0 ) {
78          work();
79      }
80      return  0 ;
81  }
View Code 

1990  MooFest

题意:给定n个pair型,对于每一对pair型,ans+=max(a.first,b.first) * abs(a.second - b.second),求最后的结果。

思路:按照first排序,然后树状数组维护

ExpandedBlockStart.gif
 1  #include <cstdio>
 2  #include <cstring>
 3  #include <algorithm>
 4  const  int  N =  200000  +  10 ;
 5  typedef  long  long  ll;
 6  struct  node {
 7      int  pos;
 8      ll v;
 9  };
10 
11  node ar[N];
12 
13  struct  Bit {
14      ll sum[N];
15      void  clear() {
16          memset(sum,  0 sizeof  sum);
17      }
18      void  add( int  pos, ll v) {
19          if  (pos ==  0 ) sum[ 0 ] += v;
20          else  {
21              for  (;pos < N; pos += pos & -pos)
22                  sum[pos] += v;
23          }
24      }
25      ll query( int  pos) {
26          if  (pos <  0 return  0 ;
27          else  {
28              ll re = sum[ 0 ];
29              for  (;pos >  0 ; pos -= pos & -pos)
30                  re += sum[pos];
31              return  re;
32          }
33      }
34  };
35 
36  Bit a, b;
37  int  n;
38 
39  bool  cmp( const  node& a,  const  node&  b) {
40      return  a.v < b.v;
41  }
42  void  work() {
43      a.clear(); b.clear();
44 
45      for  ( int  i =  0 ; i < n; ++i)
46          scanf( " %d%d " , &ar[i].v, &ar[i].pos);
47 
48      std::sort(ar, ar + n, cmp);
49 
50      ll ans =  0 , tot =  0 ;
51      for  ( int  i =  0 ; i < n; ++i) {
52          ll w = a.query(ar[i].pos);
53          ll n1 = b.query(ar[i].pos);
54 
55          ans += (n1 * ar[i].pos - w) * ar[i].v + (tot - w - (i - n1) * ar[i].pos) * ar[i].v;
56  //         printf("%lld\n", ans);
57          a.add(ar[i].pos, ar[i].pos);
58          b.add(ar[i].pos,  1 );
59 
60          tot = tot + ar[i].pos;
61      }
62 
63      printf( " %lld\n " , ans);
64  }
65  int  main() {
66      while  ( 1  == scanf( " %d " , &n)) {
67          work();
68      }
69      return  0 ;
70  }
View Code 

 

poj 3109  Inner Vertices

题意:给100000个黑色点,如果两对点的连线相交于一个白色点,则此点变成黑色。问最终会有多少个点。

思路:扫描线。

预处理:1,离散化坐标 2,找出所有最长垂直线段和水平线段 3,垂直线段按照x轴坐标分类 4,水平线段按照起点x轴坐标分类(3,4的线段放入vector中)

核心:1,枚举所有横坐标x,将所有起点坐标>=x的水平线段加入(在树状数组中更新其y坐标) 2,将所有终点坐标<x的水平线段删除(用优先队列维护,队首是终点最小;同时更新树状数组) 3,此时树状数组中所有的y值对应的水平线段都是横跨垂直线段x的,更新答案。

 

ExpandedBlockStart.gif
  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <vector>
  5 #include <queue>
  6 typedef std::pair< intint> pii;
  7  const  int INF = ( int)(1e9) +  10;
  8  const  int N =  100000 +  10;
  9 
 10  int X[N], idx, Y[N], idy;
 11 
 12 pii p[N];
 13  int n;
 14 
 15 std::vector< int> ar[N];
 16 std::vector<pii> b[N];
 17  int bra[N], brb[N];
 18 
 19  int sum[N];
 20 
 21  struct node {
 22      int x, y;
 23     node() {};
 24     node( int _x,  int _y) {
 25         x = _x, y = _y;
 26     }
 27     friend  bool  operator < ( const node& a,  const node& b) {
 28          return a.x > b.x;
 29     }
 30 };
 31 std::priority_queue<node> Q;
 32 
 33  int t[N];
 34 
 35  void add( int pos,  int v) {
 36      if ( 0 == pos) sum[ 0] += v;
 37      else {
 38          for ( int i = pos; i < idy; i += i & -i)
 39             sum[i] += v;
 40     }
 41 }
 42  int query( int pos) {
 43      if (pos <  0return  0;
 44      int re = sum[ 0];
 45      for ( int i = pos; i >  0; i -= i & -i)
 46         re += sum[i];
 47      return re;
 48 }
 49 
 50 inline  int Qu( int L,  int R) {
 51      return query(R) - query(L -  1);
 52 }
 53  void work() {
 54      for ( int i =  0; i < n; ++i) {
 55         scanf( " %d%d ", &p[i].first, &p[i].second);
 56         X[i] = p[i].first; Y[i] = p[i].second;
 57     }
 58     std::sort(X, X + n); std::sort(Y, Y + n);
 59     idx = std::unique(X, X + n) - X; idy = std::unique(Y, Y + n) - Y;
 60 
 61      for ( int i =  0; i < n; ++i) {
 62         p[i].first = std::lower_bound(X, X + idx, p[i].first) - X;
 63         p[i].second = std::lower_bound(Y, Y + idy, p[i].second) - Y;
 64     }
 65      // 求出所有 垂直线
 66       for ( int i =  0; i < idx; ++i) ar[i].clear();
 67      for ( int i =  0; i < n; ++i)
 68         ar[p[i].first].push_back(p[i].second);
 69      for ( int i =  0; i < idx; ++i)
 70         std::sort(ar[i].begin(), ar[i].end());  // a[x] (y1, y2)
 71 
 72     memset(brb, - 1sizeof brb);
 73     std::fill(bra, bra + idy +  1, INF);
 74 
 75      for ( int i =  0; i < n; ++i) {
 76         bra[p[i].second] = std::min(bra[p[i].second], p[i].first);
 77         brb[p[i].second] = std::max(brb[p[i].second], p[i].first);
 78     }
 79 
 80      for ( int i =  0; i < idx; ++i) b[i].clear();
 81      for ( int i =  0; i < idy; ++i)
 82      if (bra[i] < brb[i]) {
 83         b[bra[i]].push_back(pii(brb[i], i));  // b[x1] (x2, y)
 84      }
 85 
 86      while (!Q.empty()) Q.pop();
 87     memset(sum,  0sizeof sum);
 88     memset(t,  0sizeof t);
 89 
 90      int ans =  0;
 91      for ( int i =  0; i < idx; ++i) {
 92          for ( int j =  0; j < b[i].size(); ++j) {
 93             add(b[i][j].second,  1);
 94             ++ t[b[i][j].second];
 95             Q.push(node(b[i][j].first, b[i][j].second));  // (edx, y)
 96          }
 97          while (!Q.empty() && Q.top().x < i) {
 98             add(Q.top().y, - 1);
 99             -- t[Q.top().y];
100             Q.pop();
101         }
102          if (ar[i].size() >  1) {
103             ans += Qu(ar[i][ 0], ar[i][ar[i].size() -  1]);
104              for  ( int j =  0; j < ar[i].size(); ++j) {
105                  if ( 0 == t[ar[i][j]])
106                     ++ ans;
107             }
108         }  else {
109             ans += ar[i].size();
110         }
111 
112     }
113     printf( " %d\n ", ans);
114 }
115  int main() {
116      while ( 1 == scanf( " %d ", &n)) {
117         work();
118     }
119      return  0;
120 }
View Code

四、贪心

POJ 2698 Servicing DVD Requests

五、数论

1.辗转相除法及其拓展应用

填数游戏

题意:p1(x1,y1)到p2(x2,y2)的线段上有多少个格点(x,y皆为整数) 

思路:gcd(x2-x1,y2-y1) - 1代表不连p1,p2时的答案。

x=x2-x1,y=y2-y1 ,假设答案是g,那么x,y都要可以整除g。所以g最大就是gcd(x,y)。

2.高斯消元

hdu 2262  Where is the canteen

http://blog.csdn.net/acm_cxlove/article/details/7905778

基础的高斯求概率。

设某点的期望步数为Ei。

那么目标的Ei=0。

Ei=(Enext1+Enext2……Enextk)/k+1。

整理下就是Enext1+Enext2……Enextk-k*Ei=-k

根据i点的后继结点nextj,那么从所有的后继结点走一步都可以到达i点。便是所有后继的期望平均值+1.

以此建立方程组,然后用高斯消元求解。

ExpandedBlockStart.gif
  1  #include <cstring>
  2  #include <cstdio>
  3  #include <algorithm>
  4  #include <vector>
  5  #include <cmath>
  6 
  7  typedef std::vector< double > vec;
  8  typedef std::vector<vec> mat;
  9  const  double  eps = 1e- 8 ;
 10 
 11  vec gauss_jordan( const  mat& A,  const  vec& b) {
 12      int  n = A.size();
 13      mat B(n, vec(n +  1 ));
 14      for ( int  i =  0 ; i < n; ++i)
 15          for  ( int  j =  0 ; j < n; ++j)
 16              B[i][j] = A[i][j];
 17      for  ( int  i =  0 ; i < n; ++i) B[i][n] = b[i];
 18 
 19      for  ( int  i =  0 ; i < n; ++i) {
 20          int  pivot = i;
 21          for  ( int  j = i; j < n; ++j) {
 22              if  (abs(B[j][i]) > abs(B[pivot][i])) pivot = j;
 23          }
 24          std::swap(B[i], B[pivot]);
 25 
 26          // 有无穷解或者无解
 27           if  (abs(B[i][i]) < eps)  return  vec();
 28 
 29          // 吧正在处理的未知数的系数变成1
 30           for  ( int  j = i +  1 ; j <= n; ++j) B[i][j] /= B[i][i];
 31          for  ( int  j =  0 ; j < n ;++j) {
 32              if  (i != j) {
 33                  for  ( int  k = i +  1 ; k <= n; ++k)
 34                      B[j][k] -= B[j][i] * B[i][k];
 35              }
 36          }
 37      }
 38      vec x(n);
 39      for  ( int  i =  0 ; i < n; ++i) x[i] = B[i][n];
 40      return  x;
 41  }
 42 
 43  const  int  dx[] = { 1 0 , - 1 0 };
 44  const  int  dy[] = { 0 1 0 , - 1 };
 45  const  int  M =  15  +  1 ;
 46 
 47  char  s[M][M];
 48  bool  vis[M][M];
 49 
 50  int  r, c;
 51 
 52  void  dfs( int  x,  int  y) {
 53      vis[x][y] =  true ;
 54      for  ( int  dir =  0 ; dir <  4 ; ++dir) {
 55          int  nx = x + dx[dir], ny = y + dy[dir];
 56          if  (nx >=  0  && nx < r && ny >=  0  && ny < c && !vis[nx][ny]) {
 57              if  (s[nx][ny] ==  ' . ' )
 58                  dfs(nx, ny);
 59              else  if  (s[nx][ny] ==  ' $ ' )
 60                  vis[nx][ny] =  true ;
 61          }
 62      }
 63  }
 64  void  work() {
 65      int  sx, sy;
 66      for  ( int  i =  0 ; i < r; ++i) {
 67          scanf( " %s " , s[i]);
 68          for  ( int  j =  0 ; j < c; ++j)
 69          if  (s[i][j] ==  ' @ ' ) {
 70              sx = i; sy = j;
 71          }
 72      }
 73 
 74      memset(vis,  0 sizeof  vis);
 75  //     printf("%d %d\n", sx, sy);
 76      dfs(sx, sy);
 77 
 78      bool  f =  false ;
 79      for  ( int  i =  0 ; i < r; ++i)
 80          for  ( int  j =  0 ; j < c; ++j)
 81              if  (s[i][j] ==  ' $ '  && vis[i][j])
 82                  f =  true ;
 83      if  (f) {
 84          mat A(r * c, vec(r *c,  0 ));
 85          vec b(r * c,  0 );
 86 
 87          for  ( int  i =  0 ; i < r; ++i)
 88          for  ( int  j =  0 ; j < c; ++j) {
 89              if  (s[i][j] ==  ' $ '  || !vis[i][j]) {
 90                  A[i * c + j][i * c + j] =  1 ;
 91                  continue ;
 92              }
 93 
 94              int  moves =  0 ;
 95              for  ( int  dir =  0 ; dir <  4 ; ++dir) {
 96                  int  nx = i + dx[dir], ny = j + dy[dir];
 97                  if  (nx >=  0  && nx < r && ny >=  0  && ny < c && vis[nx][ny]) {
 98                      ++moves;
 99                      A[i * c + j][nx * c + ny] = - 1 ;
100                  }
101              }
102              b[i * c + j] = A[i * c + j][i * c + j] = moves;
103          }
104          vec x = gauss_jordan(A, b);
105          if  (x.size() >  0  && fabs(x[sx * c + sy]) > eps) {
106              printf( " %.6f\n " , x[sx * c + sy]);
107          }  else  {
108              puts( " -1 " );
109  //             printf("%.6f\n", x[sx * c + sy]);
110          }
111      }  else  {
112          puts( " -1 " );
113      }
114  }
115  int  main() {
116      while  ( 2  == scanf( " %d%d " , &r, &c)) {
117          work();
118      }
119      return  0 ;
120  }
121 
122 
123  int  q(n, m) {
124      if  (m ==  1 return  1 ;
125      else  if  (m > n)  return  q(n, n);
126      else  return  q(n, m -  1 ) + q(n - m, m);
127  }
View Code 

/******************************华丽的分割线*******************************************/ 

 

炫酷算术魔法结社群赛系列(群号283513414)(举办者  ftiasch)

20130926 - 初级魔法练习

A:POJ 2443 Set Operation

题意:给我一个1000行,10000列的01矩阵,对于指定两列询问是否存在公共的1。

方法:压缩。对于给定两列,如果直接比较需要枚举1000位,我们可以每30位压缩成一个数,用二进制&运算代替枚举,则枚举次数就变成了1000/30 <= 34,起到了非凡的加速效果。

ExpandedBlockStart.gif
 1  #include <cstdio>
 2  #include <algorithm>
 3  #include <cstring>
 4 
 5  const  int  N =  10000 ;
 6  const  int  M =  35 ;
 7  int  b[N +  1 ][M];
 8 
 9  int  n;
10 
11  bool  check( int  x,  int  y) {
12      for  ( int  i =  0 ; i < M; ++i)
13          if  ((b[x][i] & b[y][i]) >  0 return  true ;
14      return  false ;
15  }
16  void  work() {
17      memset(b,  0 sizeof (b));
18 
19      int  u, v;
20      for  ( int  i =  0 ; i < n; ++i) {
21          scanf( " %d " , &u);
22          while  (u -- >  0 ) {
23              scanf( " %d " , &v);
24              b[v][i /  30 ] |=  1  << (i %  30 );
25          }
26      }
27      int  Q, x, y;
28      scanf( " %d " , &Q);
29      while  (Q -- >  0 ) {
30          scanf( " %d%d " , &x, &y);
31          if  (check(x, y))
32              puts( " Yes " );
33          else
34              puts( " No " );
35      }
36  }
37  int  main() {
38      while  ( 1  == scanf( " %d " , &n)) {
39          work();
40      }
41      return  0 ;
42  }
View Code 

B:POJ 3244 Difference between Triplets

 

关于这个公式的解释,我们可以将I,J,K看成图上三个点,那么max{I, J, K} - min{I, J, K}就是一条线段的距离然后线性扫描即可。 

ExpandedBlockStart.gif
 1  #include <cstdio>
 2  #include <algorithm>
 3  #include <cstring>
 4  typedef  long  long  ll;
 5  const  int  N =  200000 ;
 6 
 7  int  ab[N], ac[N], bc[N];
 8 
 9  int  n;
10 
11  void  gao(ll& sum,  int * num) {
12      for  ( int  i =  1 ; i < n; ++i) {
13          sum = sum + (ll)(n - i) * i * (num[i] - num[i -  1 ]);
14      }
15  }
16  void  work() {
17      int  a, b, c;
18      for  ( int  i =  0 ; i < n; ++i) {
19          scanf( " %d%d%d " , &a, &b, &c);
20          ab[i] = a - b; ac[i] = a - c; bc[i] = b - c;
21      }
22 
23      std::sort(ab, ab + n);
24      std::sort(bc, bc + n);
25      std::sort(ac, ac + n);
26 
27      ll sum =  0 ;
28      gao(sum, ab);
29      gao(sum, ac);
30      gao(sum, bc);
31 
32      printf( " %lld\n " , sum /  2 );
33  }
34  int  main() {
35      while  ( 1  == scanf( " %d " , &n)) {
36          if  ( 0  == n)  break ;
37          work();
38      }
39      return  0 ;
40  }
View Code 

20130929 - 火球术入门

A:POJ 3040 Allowance
B:POJ 3182 The Grove

20130930 - 风系魔法的基本要领

B:poj 3375  Network Connection

题意:有n台电脑,m个接口,每台电脑和接口都有属于自己的一维坐标,每个电脑都要选择一个接口连接,连接的代价是|Xi - Yj|。

n <= 2000, m <= 100000;

思路:首先O(N*M)的dp肯定可以轻松想到,d[i][j]//用前j个接口来满足前i台电脑后最小需要花费多少

这个算法复杂度太高,所以我们将它优化。我们先在Y中找最接近Xi的那个接口p,对于Xi这才是最佳答案,但是,他可能被其他接口占用,最多有n个接口会占用他,所以,上限是p+n,这个接口也可能要留给其他的接口用,所以,最多有n个接口在后面等着用这个接口,下限是p-n。由此,算法优化到了O(N^2)

ExpandedBlockStart.gif
 1  #include <cstdio>
 2  #include <algorithm>
 3  #include <cstring>
 4  #include <cmath>
 5  typedef  long  long  ll;
 6  const  ll INF = 1ll <<  60 ;
 7 
 8  const  int  N =  2000  +  10 ;
 9  const  int  M =  100000  +  10 ;
10 
11  ll d[N][N <<  1 ];
12 
13  int  L[N], R[N];
14  int  n, m;
15 
16  int  x[N], y[M];
17 
18  void  work() {
19      for  ( int  i =  1 ; i <= m; ++i)
20          scanf( " %d " , &y[i]);
21      for  ( int  i =  1 ; i <= n; ++i)
22          scanf( " %d " , &x[i]);
23 
24      std::sort(x +  1 1  + x + n);
25      std::sort(y +  1 1  + y + m);
26 
27      for  ( int  i =  1 ; i <= n; ++i) {
28          int  p = std::lower_bound(y +  1 , y + m +  1 , x[i]) - y;
29          L[i] = std::max( 1 , p - n);
30          R[i] = std::min(m, p + n);
31      }
32 
33      for  ( int  i =  0 ; i < N + N; ++i) d[ 1 ][i] = INF;
34      for  ( int  i = L[ 1 ]; i <= R[ 1 ]; ++i) d[ 1 ][i - L[ 1 ]] = abs(x[ 1 ] - y[i]);
35 
36      for  ( int  i =  2 ; i <= n; ++i) {
37          int  k = L[i -  1 ];
38          ll v = INF;
39 
40          for  ( int  j = L[i]; j <= R[i]; ++j) {
41              while  (k <= R[i -  1 ] && k < j) {
42                  v = std::min(v, d[i -  1 ][k - L[i -  1 ]]);
43                  ++k;
44              }
45              d[i][j - L[i]] = std::min(INF, v + std::abs(x[i] - y[j]));
46              //  printf("%d %d %d\n", x[i], y[j], d[i][j]);
47          }
48      }
49      ll mx = INF;
50      for  ( int  i = L[n]; i <= R[n]; ++i)
51          mx = std::min(mx, d[n][i - L[n]]);
52 
53      printf( " %I64d\n " , mx);
54  }
55  int  main() {
56      while  ( 2  == scanf( " %d%d " , &m, &n)) {
57          work();
58      }
59      return  0 ;
60  }
View Code 

C:poj 3419 Difference Is Beautiful

20131001 - 我是如何成为一名合格的小学生的?

A: HDU 3552  I can do it!

题意:给我n个pair型元素,要求我们把他们分成两组(A,B两组),使得A组中first元素的最大值+B组中second元素的最大值的和最小

思路:按照first的值排序,然后枚举A组最大值,线性扫描即可

ExpandedBlockStart.gif
 1  #include <cstdio>
 2  #include <algorithm>
 3  #include <cstring>
 4  typedef std::pair< int int > pii;
 5  int  T =  0 ;
 6 
 7  const  int  N =  100000  +  10 ;
 8  pii ar[N];
 9 
10  void  work() {
11      int  n;
12      scanf( " %d " , &n);
13      for  ( int  i =  0 ; i < n; ++i) {
14          scanf( " %d%d " , &ar[i].first, &ar[i].second);
15      }
16 
17      std::sort(ar, ar + n);
18 
19      int  ans = ( int )(1e9) *  2  +  1 ;
20      int  bmax =  0 ;
21      for  ( int  i = n -  1 ; i >=  0 ; --i) {
22  //         printf("%d\n", ans);
23          ans = std::min(ans, ar[i].first + bmax);
24          bmax = std::max(bmax, ar[i].second);
25      }
26      printf( " Case %d: %d\n " , ++T, ans);
27  }
28  int  main() {
29      int  cas;
30      scanf( " %d " , &cas);
31      while  (cas -- >  0 ) {
32          work();
33      }
34      return  0 ;
35  }
View Code 

B: HDU 3545  Board Coloring

题意:用0到255对一个4*N的格子染色,给定M组限制,对于(x1,y1,x2,y2),必须满足(x1,y1)和(x2,y2)两个格子的颜色一样,问有多少种染色方法。(N<=15)

思路:很神奇的dp题。因为要求x,y >= A x,y-1所以符合单调性。

d[x1][x2][x3][x4]//第一行已经染色了前x1格,第二行..

我们可以先预处理所有不可行的方案,然后每次更新后将这些情况的数值设置为0。

首先第一层是当前要涂的颜色。第二层表示当前要涂的行,从第1行到第4行。

ExpandedBlockStart.gif
 1  #include <cstdio>
 2  #include <algorithm>
 3  #include <cstring>
 4  #include <vector>
 5  #define  REP(i, st, ed) for (i = st; i <= ed; ++i)
 6  const  int  mod =  100000 ;
 7  const  int  N =  15  +  1 ;
 8  const  int  M =  100  +  1 ;
 9 
10  int  d[N][N][N][N];
11  bool  legal[N][N][N][N];
12 
13  int  x1[M], x2[M], y1[M], y2[M];
14  int  n, m, t =  0 ;
15 
16  int  p[ 4 ], to[ 4 ];
17  void  prepare() {
18      int  i;
19 
20      REP(p[ 0 ],  0 , n)
21      REP(p[ 1 ],  0 , n)
22      REP(p[ 2 ],  0 , n)
23      REP(p[ 3 ],  0 , n){
24          legal[p[ 0 ]][p[ 1 ]][p[ 2 ]][p[ 3 ]] =  false ;
25          REP(i,  1 , m) {
26              if  ((p[x1[i]] >= y1[i]) ^ (p[x2[i]] >= y2[i])) {
27                  legal[p[ 0 ]][p[ 1 ]][p[ 2 ]][p[ 3 ]] =  true break ;
28              }
29          }
30      }
31  }
32  void  work() {
33      scanf( " %d%d " , &n, &m);
34      for  ( int  i =  1 ; i <= m; ++i) {
35          scanf( " %d%d%d%d " , &x1[i], &y1[i], &x2[i], &y2[i]);
36          --x1[i]; --x2[i];
37      }
38 
39      prepare();
40 
41      memset(d,  0 sizeof  d);
42      d[ 0 ][ 0 ][ 0 ][ 0 ] =  1 ;
43 
44      for  ( int  i =  1 ; i <=  256 ; ++i) {
45          for  ( int  idx =  0 ; idx <  4 ; ++idx)
46          REP(p[ 0 ],  0 , n)
47          REP(p[ 1 ],  0 , n)
48          REP(p[ 2 ],  0 , n)
49          REP(p[ 3 ],  0 , n)
50          if  (d[p[ 0 ]][p[ 1 ]][p[ 2 ]][p[ 3 ]] >  0  && p[idx] +  1  <= n) {
51              ++p[idx];
52              int & t = d[p[ 0 ]][p[ 1 ]][p[ 2 ]][p[ 3 ]];
53              --p[idx];
54              t += d[p[ 0 ]][p[ 1 ]][p[ 2 ]][p[ 3 ]];
55              if  (t >= mod)
56                  t -= mod;
57          }
58          REP(p[ 0 ],  0 , n)
59          REP(p[ 1 ],  0 , n)
60          REP(p[ 2 ],  0 , n)
61          REP(p[ 3 ],  0 , n)
62          if  (legal[p[ 0 ]][p[ 1 ]][p[ 2 ]][p[ 3 ]])
63              d[p[ 0 ]][p[ 1 ]][p[ 2 ]][p[ 3 ]] =  0 ;
64      }
65      printf( " Case %d: %05d\n " , ++t, d[n][n][n][n]);
66  }
67  int  main() {
68      int  cas;
69      scanf( " %d " , &cas);
70      while  (cas -- >  0 ) {
71          work();
72      }
73      return  0 ;
74  }
View Code 

C:HDU 4014 Jimmy’s travel plan

 20131002 - 暴雨术入门

A:HDU 4103 Clock

B:HDU 4104 Discount

C:HDU 4107 Gangster

20131003 - 在沙漠中的长途旅行

A:POJ 2793 Cactus

B:POJ 3567 Cactus Reloaded

20130904 - 幽默术

A:POJ 3538 Domestic Networks

B:POJ 3566 Building for UN

C:POJ 3537 Crosses and Crosses

20131005 - 幽默大师职业赛

A:POJ 3208 Apocalypse Someday

B:POJ 3015 Expected Difference

C:POJ 3016 K-Monotonic

20131006 - 幽默大师卫冕战

A:SGU 409 Berland Flag

B:SGU 361 National Flag

C:SGU 379  Elevator
20131007 - 胜利大逃亡

A: SGU 527  Explode 'Em All

题意:在一个25*25的地图中放置炸弹,消灭所有的山。一个炸弹可以消灭所在行和所在列的所有山。

方法:搜索。假设我们已经选取了i行要放置炸弹,那么还有j行的山要消灭,那么这些山只能靠这i行的炸弹来消灭,如果剩下的炸弹所用的列小于等于i,那么答案就是i。根据这点深搜。

ExpandedBlockStart.gif
 1  #include <cstdio>
 2  #include <cstring>
 3  #include <algorithm>
 4  const  int  N =  30 ;
 5 
 6  char  s[N];
 7  int  r, c;
 8 
 9  int  sta[N], ans;
10 
11  void  dfs( int  idx,  int  sx,  int  cntx,  int  sy,  int  cnty) {
12      if  (std::max(cntx, cnty) >= ans)  return  ;
13      if  (idx == r) {
14          ans = std::min(ans, std::max(cntx, cnty));
15      }  else  {
16          if  (sta[idx] >  0 ) {
17              int  to = sy | sta[idx];
18              if  (to == sy)
19                  dfs(idx +  1 , sx, cntx, sy, cnty);
20              else  {
21                  int  cc =  0 ;
22                  for  ( int  i =  0 ; i < c; ++i)
23                      if  (to >> i &  1 )
24                          ++cc;
25                  dfs(idx +  1 , sx, cntx, to, cc);
26              }
27              dfs(idx +  1 , sx | ( 1  << idx), cntx +  1 , sy, cnty);
28          }  else  {
29              dfs(idx +  1 , sx, cntx, sy, cnty);
30          }
31      }
32  }
33  void  work() {
34      memset(sta,  0 sizeof  sta);
35 
36      for  ( int  i =  0 ; i < r; ++i) {
37          scanf( " %s " , s);
38          for  ( int  j =  0 ; j < c; ++j)
39              if  (s[j] ==  ' * ' )
40                  sta[i] |=  1  << j;
41      }
42 
43      ans = std::max(r, c);
44      dfs( 0 0 0 0 0 );
45 
46      printf( " %d\n " , ans);
47  }
48  int  main() {
49      while  ( 2  == scanf( " %d%d " , &r, &c)) {
50          work();
51      }
52      return  0 ;
53  }
View Code 

B:CodeForces 37C Old Berland Language

C:CodeForces 40E Number Table

20131008 - 想不出名字了呜

A:HDU 3434 Sequence Adjustment

B:HDU 4275 Color the Tree

C:HDU 4270 Dynamic Lover

2013 ACM亚洲赛网络赛系列 

B:An Easy Problem for Elfness

E:Round Table

F:G(x)

H:Little Wish~ lyrical step~

杭州赛区:

D:Save Labman No.004

E:Pinball Game 3D

G:Starloop System

J:  Mex

题解链接: http://www.cnblogs.com/hewifi/p/3329168.html

长春赛区:

A:Poker Shuffle

B:Good Firewall

H:Network

I:Bell

J:  Flyer

二分不幸运的人所在的位置,由于不幸运的人只有一个,所以如果有人不幸运,那么任何从起点开始,终点>=此人位置的区间中,被发放的海报的总数一定是奇数,否则就一定是偶数,由此满足单调性。

ExpandedBlockStart.gif
 1  #include <cstdio>
 2  #include <algorithm>
 3  #include <cstring>
 4  #include <vector>
 5  typedef __int64 ll;
 6  const  ll INF = 1ll <<  32 ;
 7  const  int  N =  20000  +  10 ;
 8 
 9  ll a[N], b[N], c[N];
10  int  n;
11 
12  bool  judge(ll x) {
13      ll tot =  0 ;
14      for  ( int  i =  0 ; i < n; ++i) {
15          if  (x < a[i])  continue ;
16          if  (x >= b[i]) {
17              tot = tot +  1  + (b[i] - a[i]) / c[i];
18          }  else  {
19              tot = tot +  1  + (x - a[i]) / c[i];
20          }
21          tot = tot &  1 ;
22      }
23      return  tot &  1 ;
24  }
25  void  work() {
26      for  ( int  i =  0 ; i < n; ++i)
27          scanf( " %I64d%I64d%I64d " , &a[i], &b[i], &c[i]);
28      ll l =  0 , r = INF, mid;
29      while  (r - l >  1 ) {
30          mid = (l + r) /  2 ;
31          if  (judge(mid))
32              r = mid;
33          else
34              l = mid;
35      }
36 
37      if  (judge(r)) {
38          int  cnt =  0 ;
39          for  ( int  i =  0 ; i < n; ++i) {
40              if  (r < a[i] || r > b[i])  continue ;
41              if  ((r - a[i]) % c[i] ==  0 )
42                  ++cnt;
43          }
44          printf( " %I64d %d\n " , r, cnt);
45      }  else
46          puts( " DC Qiang is unhappy. " );
47  }
48  int  main() {
49      while  ( 1  == scanf( " %d " , &n)) {
50          work();
51      }
52      return  0 ;
53  }
View Code   

 

 

6th BUPT Programming Contest Final

A:UESTC 1697 Palindrome Again

这一题本质上是求两个串有多少对公共回文子串,只考虑子串的起始位置和长度的不同。

E:UESTC 1701 PAC-Phone

给你两个点集问是否相似。

H:UESTC 1704 Running

I:  UESTC 1705  The Longest Sequence of Rectangles

题意:n个矩形的lis,需要严格满足第i个矩形的左下角坐标严格大于第i-1个矩形的右上角坐标。

思路:树状数组\线段树。首先将所有点先按照x轴坐标从小到大排序,如果x轴坐标一样,那么终点总是在起点后面,如果是同一性质的点,为了严格递增,按照y轴坐标从大到小排序(如果是不严格则从小到大)。然后用树状数组或者线段树维护。如果遇到的是起点,则更新数组中的值,如果是终点,则将此点插入数据结构中。

ExpandedBlockStart.gif
 1  #include <cstring>
 2  #include <cstdio>
 3  #include <algorithm>
 4  struct  node {
 5      int  x, y, typ, id;
 6  };
 7 
 8  #define  lson l, mid, rt << 1
 9  #define  rson mid + 1, r, rt << 1 | 1
10  const  int  N =  200000  +  5 ;
11 
12  int  val[N];
13 
14  node p[N];
15  int  y[N], idy;
16 
17  int  len[N];
18  int  query( int  R) {
19      int  re =  0 ;
20      for  (; R >  0 ; R -= R & -R) {
21          re = std::max(re, val[R]);
22      }
23      return  re;
24  }
25  void  update( int  pos,  int  v) {
26      for  (; pos <= idy; pos += pos & -pos)
27          val[pos] = std::max(val[pos], v);
28  }
29  bool  cmp( const  node& a,  const  node& b) {
30      if  (a.x ^ b.x)  return  a.x < b.x;
31      else  {
32          if  (a.typ ^ b.typ)  return  a.typ < b.typ;
33          else  return  a.y > b.y;
34      }
35  }
36  void  work() {
37      int  n;
38      scanf( " %d " , &n);
39 
40      idy =  0 ;
41      for  ( int  i =  0 ; i < n; ++i) {
42          scanf( " %d%d " , &p[i <<  1 ].x, &p[i <<  1 ].y);
43          p[i <<  1 ].typ =  0 ;
44 
45          scanf( " %d%d " , &p[i <<  1  |  1 ].x, &p[i <<  1  |  1 ].y);
46          p[i <<  1  |  1 ].typ =  1 ;
47 
48          p[i <<  1  |  1 ].id =  p[i <<  1 ].id = i;
49 
50          y[idy ++] = p[i <<  1 ].y;
51          y[idy ++] = p[i <<  1  |  1 ].y;
52      }
53      std::sort(y, y + idy);
54      idy = std::unique(y, y + idy) - y;
55 
56      n <<=  1 ;
57      for  ( int  i =  0 ; i < n; ++i) {
58          p[i].y = std::lower_bound(y, y + idy, p[i].y) - y +  1 ;
59      }
60 
61      memset(val,  0 sizeof ( int ) * (idy +  2 ));
62 
63      int  mx, ans =  1 ;
64 
65      std::sort(p, p + n, cmp);
66      memset(len,  0 sizeof  len);
67      for  ( int  i =  0 ; i < n; ++i) {
68          if  ( 0  == p[i].typ) {
69              len[p[i].id] = std::max(len[p[i].id],  1  + query(p[i].y -  1 ));
70              ans = std::max(ans, len[p[i].id]);
71          }  else  {
72              update(p[i].y, len[p[i].id]);
73          }
74      }
75      printf( " %d\n " , ans);
76  }
77  int  main() {
78      int  cas;
79      scanf( " %d " , &cas);
80      while  (cas -- >  0 ) {
81          work();
82      }
83      return  0 ;
84  }
View Code 

 

ICPC Latin American Regional 2011 - South America/South 

C:UVALive 5791 Candy's Candy

题意: 

有f种口味的糖果,现在要把每颗糖果分到一些packs里面去。packs分两种:

flavored pack:只有一种口味。

variety pack:每种口味都有。

求满足下列要求的分法有多少种:

1、每个pack至少有两颗糖果。

2、所有pack的糖果数相同。

3、variety pack 里每种口味的糖果数量相同。

4、至少一个variety pack。

5、每种口味至少一个flavored pack。

D:UVALive 5792 Diccionário Portuñol

题意:给你两种串,一种可以当前缀,一种可以当后缀,问两种串合起来,一共有多少种组合。并且没有重合。

F:UVALive 5794 File Retrieval 

题意:给你n个串,现在有一个搜索系统,对于任意一个串s,它能够返回所有包含s这个子串的串的集合。

询问一共有多少种可能的返回集合。对于所有的串s。规模:60个串,每个串长度10^4。

 

转载于:https://www.cnblogs.com/hewifi/p/3342772.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值