JOI春合宿2012 Day3

昨日よりましになった。リス(3完)

Fortune Telling

Segment Tree×平面走査やるだけ

#include <cstdio>
#include <algorithm>
#include <vector>

using namespace std;

typedef long long i64;
const int MAX = 100000;

struct seg_tree
{
  static const int DEPTH = 18;
  static const int SZ = 1<<DEPTH;
  i64 weight[SZ*2], stat[SZ*2]; int swap[SZ*2];

  seg_tree()
  {
    for(int i=0;i<2*SZ;i++){
      weight[i] = stat[i] = 0;
      swap[i] = 0;
    }
  }

  void init(int* v, int ln)
  {
    for(int i=0;i<ln;i++) weight[i+SZ] = v[i];
    for(int i=ln;i<SZ;i++) weight[i+SZ] = 0;
    for(int i=SZ-1;i>=1;i--) weight[i] = weight[i*2] + weight[i*2+1];
  }

  void flip(int pL, int pR, int qL, int qR, int depth)
  {
    //printf("%d %d %d %d %d\n", pL, pR, qL, qR, depth);
    if((pR<<depth)<=qL || qR<=(pL<<depth)) return;
    if(qL<=(pL<<depth) && (pR<<depth)<=qR){
      stat[pL] = weight[pL] - stat[pL];
      swap[pL] ^= 1;
      return;
    }
    
    if(swap[pL]){
      swap[pL] = 0;
      swap[pL*2] ^= 1; stat[pL*2] = weight[pL*2] - stat[pL*2];
      swap[pL*2+1] ^= 1; stat[pL*2+1] = weight[pL*2+1] - stat[pL*2+1];
    }
    flip(pL*2, pL+pR, qL, qR, depth-1);
    flip(pL+pR, pR*2, qL, qR, depth-1);
    stat[pL] = stat[pL*2] + stat[pL*2+1];
  }

  void flip(int qL, int qR)
  {
    flip(1, 2, qL+SZ, qR+SZ, DEPTH);
  }

  i64 sum()
  {
    return stat[1];
  }
};

struct action
{
  int pos, left, right;
  action(){ }
  action(int _l, int _r, int _p){ pos = _p; left = _l; right = _r; }
};

inline bool operator<(const action& A, const action& B)
{
  return A.pos < B.pos;
}

int M, N, K;
int x1[MAX], x2[MAX], y1[MAX], y2[MAX];
int xs[2*MAX], xln, dif[2*MAX];
seg_tree seg;
action act[2*MAX];

int main()
{
  scanf("%d%d%d", &M, &N, &K);
  for(int i=0;i<K;i++){
    scanf("%d%d%d%d", x1+i, x2+i, y1+i, y2+i);
    --x1[i]; --y1[i];
    xs[i*2] = x1[i];
    xs[i*2+1] = x2[i];
  }
  sort(xs, xs+2*K);
  xln = unique(xs, xs+2*K) - xs;
  for(int i=0;i<xln-1;i++) dif[i] = xs[i+1] - xs[i];
  seg.init(dif, xln-1);
  for(int i=0;i<K;i++){
    act[i*2] = action(lower_bound(xs, xs+xln, x1[i])-xs, lower_bound(xs, xs+xln, x2[i])-xs, y1[i]);
    act[i*2+1] = action(lower_bound(xs, xs+xln, x1[i])-xs, lower_bound(xs, xs+xln, x2[i])-xs, y2[i]);
  }
  sort(act, act+2*K);
  i64 ret = 0;
  for(int i=0;i<2*K;i++){
    if(i>0) ret += seg.sum() * (act[i].pos - act[i-1].pos);
    seg.flip(act[i].left, act[i].right);
    //printf("%lld\n", seg.sum());
  }

  printf("%lld\n", (i64)M*N - ret);

  return 0;
}

Kangaroo

適当に DP をやると通る

#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

typedef long long i64;
const i64 MOD = 1000000007;
const int MAX = 300;

#define ADD(X,Y) ( (X) = ( (X) + (Y) ) % MOD )

int N, A[MAX], B[MAX];

i64 dp[2][MAX+1][MAX+1];

int main()
{
  scanf("%d", &N);
  for(int i=0;i<N;i++) scanf("%d%d", A+i, B+i);
  sort(A, A+N); sort(B, B+N);
  reverse(A, A+N); reverse(B, B+N);

  int bp = 0, t = 0, cFree;
  for(int i=0;i<=N;i++)
    for(int j=0;j<=N;j++) dp[0][i][j] = dp[1][i][j] = 0;
  dp[t][0][0] = 1;

  for(int i=0;i<N;i++){
    while(bp<N && A[i]<B[bp]) bp++;
    for(int j=0;j<=N;j++)
      for(int k=0;k<=N;k++) dp[1-t][j][k] = 0;
    for(int j=0;j<=N;j++)
      for(int k=0;k<=N;k++){
	if(!dp[t][j][k]) continue;
	cFree = bp - j - k;

	//A: not connect
	ADD(dp[1-t][j][k+cFree], dp[t][j][k]);
	if(k>0) ADD(dp[1-t][j+1][k-1], dp[t][j][k] * k);
	ADD(dp[1-t][j+1][k], dp[t][j][k] * cFree);
      }
    t = 1-t;
  }

  i64 ret = 0;
  for(int i=0;i<=N;i++) ADD(ret, dp[t][i][0]);
  printf("%lld\n", ret);

  return 0;
}

Sokoban

関節点っぽいものを求めると解ける

#include <cstdio>
#include <queue>
#include <algorithm>

using namespace std;
typedef long long i64;
typedef pair<pair<int, int>, int> bfsdat;

const int MAX = 1010;

struct union_find
{
  int val[4];
  union_find(){ val[0]=val[1]=val[2]=val[3]=-1; }
  int root(int p){ return (val[p]<0)?p:(val[p]=root(val[p])); }
  void join(int p, int q)
  {
    p = root(p); q = root(q); if(p==q) return;
    val[p] += val[q]; val[q] = p;
  }
};

int M, N;
char in[MAX][MAX];
int ax[4]={-1,0,1,0},ay[4]={0,1,0,-1}; //up, right, down, left
bool vis[MAX][MAX];
int idx[MAX][MAX], iLast; int decl[MAX][MAX][4];
int wayGoing[MAX][MAX];
union_find con[MAX][MAX];
int weight[MAX][MAX][4];

int calc_size(int px, int py)
{
  int ret = (in[px][py]=='.') ? 1 : 0;
  vis[px][py] = true;
  for(int i=0;i<4;i++){
    if(in[px+ax[i]][py+ay[i]]=='#') continue;
    if(!vis[px+ax[i]][py+ay[i]]) ret += calc_size(px+ax[i], py+ay[i]);
  }

  return ret;
}

pair<int, int> dfs(int px, int py, int fw, int gsize)
{
  idx[px][py] = iLast++;
  int count=(in[px][py]=='.') ? 1 : 0, ef=0;

  for(int i=0;i<4;i++){
    if(i==fw) continue;
    if(in[px+ax[i]][py+ay[i]]=='#') continue;
    if(idx[px+ax[i]][py+ay[i]]!=-1){
      //ever visited
      if(idx[px+ax[i]][py+ay[i]] < idx[px][py]){
	//parent
	decl[px+ax[i]][py+ay[i]][wayGoing[px+ax[i]][py+ay[i]]]++;
	ef++;
	con[px][py].join(fw, i);
	con[px+ax[i]][py+ay[i]].join((i+2)%4, wayGoing[px+ax[i]][py+ay[i]]);
      }else{
	//child
	//join something;;;
      }
    }else{
      //not visited yet
      wayGoing[px][py] = i;
      pair<int, int> stat = dfs(px+ax[i], py+ay[i], (i+2)%4, gsize);
      count += stat.first;
      weight[px][py][i] = stat.first;

      int eTmp = stat.second - decl[px][py][i];
      if(eTmp) con[px][py].join(i, fw);
      ef += eTmp;
    }
  }
  weight[px][py][fw] = gsize - count;

  return make_pair(count, ef);
}

bool bfsVis[MAX][MAX][4];
int bx, by;

void bfs()
{
  queue<bfsdat> q;
  for(int i=0;i<4;i++){
    if(in[bx+ax[i]][by+ay[i]]=='.')
      q.push(make_pair(make_pair(bx, by), i));
  }

  int px, py, w;
  while(!q.empty()){
    bfsdat tmp = q.front(); q.pop();
    if(bfsVis[tmp.first.first][tmp.first.second][tmp.second]) continue;
    bfsVis[tmp.first.first][tmp.first.second][tmp.second] = true;

    //back
    px = tmp.first.first; py = tmp.first.second; w = tmp.second;
    if(in[px+ax[w]*2][py+ay[w]*2]!='#'){
      q.push(make_pair(make_pair(px+ax[w], py+ay[w]), w));
    }
    
    //move other side
    for(int i=0;i<4;i++){
      if(i != w && con[px][py].root(i) == con[px][py].root(w)){
	q.push(make_pair(make_pair(px, py), i));
      }
    }
  }

}

int main()
{
  scanf("%d%d", &M, &N);
  for(int i=1;i<=M;i++){
    scanf("%s", in[i]+1);
    in[i][0] = in[i][N+1] = '#';
    in[i][N+2] = '\0';
  }
  for(int i=0;i<=N+1;i++) in[0][i] = in[M+1][i] = '#';
  in[0][N+2] = in[M+1][N+2] = '\0';
  M += 2; N += 2;

  for(int i=0;i<M;i++)
    for(int j=0;j<N;j++){
      vis[i][j] = false; idx[i][j] = -1;
      for(int k=0;k<4;k++){
	weight[i][j][k] = 0;
	bfsVis[i][j][k] = false;
	decl[i][j][k] = 0;
      }
      if(in[i][j]=='X'){
	bx = i; by = j;
      }
    }

  iLast = 0;
  for(int i=1;i<M-1;i++)
    for(int j=1;j<N-1;j++) if(in[i][j]!='#' && idx[i][j]==-1){
	int sz = calc_size(i, j);
	dfs(i, j, -1, sz);
      }
  
  bfs();

  i64 ret = 0;
  for(int i=1;i<M-1;i++){
    for(int j=1;j<N-1;j++){
      if(in[i][j]=='.'){
	for(int k=0;k<4;k++){
	  if(bfsVis[i][j][k]) ret += weight[i][j][k];
	}
      }
    }
  }

  printf("%lld\n", ret);

  return 0;
}