見出し画像

D - Double Landscape

[Q] https://atcoder.jp/contests/keyence2019/tasks/keyence2019_d

BITで80msくらい。1度ACすると効率化できるのがわかる。でもバグりそう。
0.  A[] も B[] も順番関係ないので、sortしておくと考えやすいかも。
1. 一番大きい数 N*M から盤面に入れていくことを考える。1まで探索。
次の4通りで場合分け。
2. 盤面に入れる数字 x を、N*M ~ 1 まで探索していく。もしxがAに2つ以上あれば実現不可能なので0。Bに2つ以上あっても0。
2. xがAとBどちらにもあったら、確定置き1マス。
2. xがAだけにあったら、x以上のBならどこでもおける。
2. xがBだけにあったら、x以上のAならどこでもおける。
2. xがAにもBにもなかったら、x以上のA * B ならどこでも置ける。

Q. 例
3 3
5 7 9
6 8 9

0. sortする
  6 8 9
5
7
9

1. N*M = 9 から埋めていくことを考える。
答えの初期値は 1通り
ans = 1

2) 9 を入れる
used = 0 // 置いたマス数を数えておく

A にも B にも 9 があるので、(2,2)に確定入れ。
  6 8 9
5
7
9    [9]

選択の余地は 1通り しかない。
ans *= 1 // 1
used = 1

2) 8 を入れる
A に指定があるので、Bのおける範囲を考える。
8以上のBは{9}で1要素。結果(2,1)しかおけない
  6 8 9
5
7
9   x 9
ans *= 1 //1
used = 2

2) 7 を入れる
B に指定があるので、A のおける範囲を考える。
7以上のAは、{8,9}で2要素。(1,1)と(1,2)における。
  6 8 9
5
7   x x
9   8 9
選択の余地は 2通り なので
ans *= 2 // 2
used = 3

2) 6 を入れる。
A に指定があるので、B のおける範囲を考える。
6 以上の B は{7,9}で2要素。
  6 8 9
5
7 x   7
9 x 8 9
x の2通りにおけるので、
ans *= 2 // 4
used = 4

2) 5 を入れる。
B に指定があるので、A のおける範囲を考える。
5以上のAは {6, 8, 9} で3要素。
  6 8 9
5 x x x
7     7
9 6 8 9
3 箇所に入るので、
ans *= 3 // 12
used = 5

2) 4 を入れる。
A にも B にもない。
ということは、4以上であればどこでも入れていい。

  6 8 9
5 5 x x
7 x x 7
9 6 8 9
4以上のAは{6,8,9} で3要素
4以上のBは{5,7,9} で3要素
ここまでで used = 55マス使っているので、3*3 - 5 = 9 - 5 = 4マスなら自由に選べる。
ans *= 4 // 48
used = 6

2) 3 を入れる。
  6 8 9
5 5 4 x
7 x x 7
9 6 8 9
3マス入れられるので * 3

以降同じ。

ans = 48 * 3 * 2 * 1だと思う。

実装

vector<ll> A[1000010];
vector<ll> B[1000010];
ll N, M;
int main(){
 cincout();
 
 cin >> N >> M;
 Bit<1000010> yoko, tate; //1000*1000まで
 rep(i, N){
   ll a;
   cin >> a;
   yoko.add(a, 1);
   A[a].push_back(i);
 }
 rep(i, M){
   ll b;
   cin >> b;
   tate.add(b, 1);
   B[b].push_back(i);
 }
 mint ans=1;
 ll cnt=0; // 使った数
 // 大きい数からうめてく
 for(ll i=N*M; i>0; --i){
   ll asz = A[i].size();
   ll bsz = B[i].size();
   mint div = 0;
   ll all = yoko.rangesum(i, N*M+1) * tate.rangesum(i, N*M+1) - cnt;
   // 1. 最大値が 2個以上, はありえないので終了
   if (asz>1 || bsz>1){
     cout << 0 << endl;
     return 0;
   }
   // 1. AもBも指定なら確定1マス
   else if(asz==1 && bsz==1) div = 1;
   // 1. Aだけ指定なら、i以上のBマスならどこでもおける
   else if(asz==1 && bsz==0){
     div = tate.rangesum(i, N*M+1);
   }
   // 1. Bだけ指定なら、i以上のAマスならどこでもおける
   else if(asz==0 && bsz==1){
     div = yoko.rangesum(i, N*M+1);
   }
   // 1. 指定なしなら、i以上のマスならどこでもおける
   else if(asz==0 && bsz==0){
     div = max(all, 0LL);
   }
   ans *= div;
   ++cnt;
 }
 cout << ans << endl;
}

Q. バグ
A. N*M+1 とすべきところ、N*N+1 とか、 N+M*1 とか。永遠にタイポした。

https://atcoder.jp/contests/keyence2019/submissions/27493884

この記事が気に入ったらサポートをしてみませんか?