Codeforces Round #285 DIV1 C問題/DIV2 E問題 - Misha and Palindrome Degree

Source

Codeforces Round #285 DIV1 C問題
Codeforces Round #285 DIV2 E問題
Problem description

問題概要

$N$ 要素の数列 $A_1,A_2,\ldots,A_N$ が与えられる.
これが回文列であるとは,$A_k = A_{N-k+1}$ が全ての $k$ に対して満たされる,つまり,反転しても同じことを指す.
$[l,r], \;\; 1 \leq l \leq r$ という区間で,$A_l,A_{l+1},\ldots,A_r$ を自由に入れ替えることで,$A_1,A_2,\ldots,A_N$ を回文列にできるようなものはいくつあるかを求める問題.

解法

まず,奇数回だけ登場する要素の数が高々 $1$ であるかどうかをチェックする.
同時に,$N$ が奇数の場合は,奇数回だけ出てくる要素を覚えておく.
これが $2$ 個以上あれば,どうやっても回文列にできないので答えは $0$.
逆に,$1$ 個以下であれば,全てを並び替えれるならば回文列にできる.
また,$[l,r]$ 内の要素を入れ替えることで回文列にできるなら,それを含む区間 $[a,b]$ 内の要素を入れ替えることでも回文列を作れる.
次に,$A_i \neq A_{N-i+1}$ となる最小の $i$ を見つけてくる.
入れ替える区間は,$i$ または $N-i+1$ を含まなければ,回文列にできないことがわかる.
入れ替えると回文列にできる区間 $[i,a], [b,N-i+1]$ の中で最小の $a$,および,最大の $b$ を求める.
すると,ある区間内の要素を入れ替えて回文列にできるための必要十分条件は,$[i,a]$ と $[b,N-i+1]$ の少なくてもどちらか一方を含む,ということになる.
よって,包除原理により,$[i,a]$ が含まれる区間の数 $+$ $[b,N-i+1]$ が含まれる区間の数 $-$ 両方の区間が含まれる数,により,答えを求めることができる.
つまり,$a,b$ を求めれば良いことになる.
以下では,$a$ を求めることを考える.
最も,真ん中に近い不一致の場所,$A_k \neq A_{N-k+1}, \;\; k < N-k+1$ を満たす最大の $k$ を考えると,$a$ は $k$ 以上でなければいけない.
また,$N$ が奇数で,真ん中の要素 $A_{(N+1)/2}$ が奇数個のものでなければ $a$ は $(N+1)/2$ 以上でなければいけない.
$k$ を $i$ から増やしていくことを考えると,$A_k$ を $1$ つ自由に使えるようになり,$A_{N-k+1}$ を $1$ つ使わなければいけない,とカウントしていく.
ただし,$k$ がちょうど真ん中の場合は,必要になるのは偶数個の要素で,$k$ が真ん中を過ぎると,対応するところで必要となるものが必要でなくなるとともに,$A_k$ も自由にできるので,新しく必要になるものがなく,自由にできるものが $2$ つ増える.
こうやって進めていき,全ての要素に対して,自由になるものの数が必要になるものの数以上となり,かつ,上の~以上でなければいけないという条件を満たす最初の場所が $a$ の最小値になる.
時間計算量は $O(N)$ となる.

C++のスパゲッティなコード

#include<bits/stdc++.h>
using namespace std;

#define REP(i,a,b) for(i=a;i<b;i++)
#define rep(i,n) REP(i,0,n)

#define READER_BUF_SIZE 1048576
#define WRITER_BUF_SIZE 1048576
int reader_pt=READER_BUF_SIZE,reader_last;char reader_buf[READER_BUF_SIZE];
int writer_pt=0;char writer_buf[WRITER_BUF_SIZE];
#define mygc(c) {if(reader_pt==READER_BUF_SIZE)reader_pt=0,reader_last=fread(reader_buf,sizeof(char),READER_BUF_SIZE,stdin);(c)=reader_buf[reader_pt++];}
#define mypc(c) {if(writer_pt==WRITER_BUF_SIZE)writer_pt=0,fwrite(writer_buf,sizeof(char),WRITER_BUF_SIZE,stdout);writer_buf[writer_pt++]=(c);}
#define myed {fwrite(writer_buf,sizeof(char),writer_pt,stdout);writer_pt=0;}

#define ll long long
#define ull unsigned ll

void reader(int *x){int k,m=0;*x=0;for(;;){mygc(k);if(k=='-'){m=1;break;}if('0'<=k&&k<='9'){*x=k-'0';break;}}for(;;){mygc(k);if(k<'0'||k>'9')break;*x=(*x)*10+k-'0';}if(m)(*x)=-(*x);}
void writer(ll x, char c){int s=0,m=0;char f[20];if(x<0)m=1,x=-x;while(x)f[s++]=x%10,x/=10;if(!s)f[s++]=0;if(m)mypc('-');while(s--)mypc(f[s]+'0');mypc(c);}
template<class T> void writerLn(T x){writer(x,'\n');}

int N;
int A[200000];
int cnt[200000];

int need[200000], dame;

ll solve(void){
  int i, j, k, x, y;
  int odd = 0;
  int a, b, c, d;
  int a1, a2, b1, b2;
  ll res;

  rep(i,N) A[i]--;
  rep(i,N) cnt[i] = 0;
  rep(i,N) cnt[A[i]]++;
  rep(i,N) odd += cnt[i] % 2;
  if(odd > 1) return 0;
  if(N%2==0 && odd) return 0;

  res = (ll)N * (N+1) / 2;
  rep(i,N) if(A[i] != A[N-1-i]) break;
  if(i==N) return res;

  a = c = N;
  b = d = -1;
  
  if(N%2==0){
    rep(i,N/2){
      if(A[N/2+i] == A[N/2-1-i]) continue;
      a = min(a, N/2-1-i);
      b = max(b, N/2-1-i);
      c = min(c, N/2+i);
      d = max(d, N/2+i);
    }
  } else {
    rep(i,N) if(cnt[i]%2) odd = i;
    rep(i,N/2+1){
      if(A[N/2+i] == A[N/2-i] && i) continue;
      if(i==0 && odd == A[N/2]) continue;
      a = min(a, N/2-i);
      b = max(b, N/2-i);
      c = min(c, N/2+i);
      d = max(d, N/2+i);
    }
  }

  dame = 0;
  rep(i,N) need[i] = 0;
  for(i=a;i<N;i++){
    x = A[i];
    y = A[N-1-i];
    if(i!=N-1-i){
      if(i<N-1-i){ need[y]++; if(need[y]>0) dame++; }
      else if(i<=d){ if(need[x]>0) dame--; need[x]--; }
      if(need[x]>0) dame--; need[x]--;
    } else {
      need[odd]++; if(need[odd]>0) dame++;
      if(need[x]>0) dame--; need[x]--;
    }

    if(i >= b && dame==0){
      a1 = a; b1 = i;
      break;
    }
  }

  dame = 0;
  rep(i,N) need[i] = 0;
  for(i=d;;i--){
    x = A[i];
    y = A[N-1-i];
    if(i!=N-1-i){
      if(i>N-1-i)  { need[y]++; if(need[y]>0) dame++; }
      else if(i>=a){ if(need[x]>0) dame--; need[x]--; }
      if(need[x]>0) dame--; need[x]--;
    } else {
      need[odd]++; if(need[odd]>0) dame++;
      if(need[x]>0) dame--; need[x]--;
    }

    if(i <= c && dame==0){
      a2 = i; b2 = d;
      break;
    }
  }
  
  res = 0;
  res += (ll)(a1+1) * (N-b1);
  res += (ll)(a2+1) * (N-b2);
  a1 = min(a1, a2);
  b1 = max(b1, b2);
  res -= (ll)(a1+1) * (N-b1);

  return res;
}

ll brute(void){
  int i, j, k, a, b;
  int arr[100];
  int res = 0;

  rep(a,N) REP(b,a,N){
    rep(i,N) arr[i] = A[i];
    sort(arr+a, arr+b+1);
    do{
      rep(i,N) if(arr[i] != arr[N-1-i]) break;
      if(i==N){ res++; break; }
    }while(next_permutation(arr+a,arr+b+1));
  }

  return res;
}

int main(){
  int i;
  ll res, buf;

  reader(&N);
  rep(i,N) reader(A+i);

  res = solve();
  writerLn(res);

  myed;
  return 0;
}

Current time: 2017年11月18日11時42分20秒
Last modified: 2015年01月16日07時19分04秒 (by laycrs)
Tags: Competitive_Programming Codeforces CF285 CF_Div1_C CF_Div2_E
トップページに戻る

Logged in as: unknown user (not login)

ログイン: