USACO2020JAN Platinum T2 positive solutions official translation?

USACO2020JAN Platinum T2 positive solutions official translation?

This question is feeling short-lived fad do not know about

Therefore, the translation of the article again, and then in the form of annotations to speak very clearly understand the following places again.

(Benjamin Qi analysis)

The following order \ (^. 9 + 10 = the MOD. 7 \) .

Some constant optimization techniques:

  • The \ (MOD \) is defined as constants.
  • Plus or minus two intavoided when using the% operator.
  • For proof mentioned below, the use of fixed-size two-dimensional array storage (not in c ++ vector set vector).
  • Not have to traverse the matrix entries equal to zero (i.e., the lower portion of the rear diagonal matrix hereinafter).

A definition of the individual classes modulo operation (or struct) cards normally will also help.

For convenience, we consider the range of values is \ ([0, N) \ ) instead of \ ([1, N] \) .

While the later will use variables had previously used

Subtask 1:

We can \ (O (NK ^ 2) \) each of the calculation complexity \ ((L, R) ( 1 \ le L \ le R \ le N) \) answers.

Specifically, we enumerate the left point \ (L \) , then let \ (R = L \) and then continue to increment \ (R \) .

With \ (tot_i \) represents a digital \ (i (i \ in [ 0, K) \) \) at the end of the sequence number is not a drop. (Seen as the zero sequence ending with blank)

Then one by one in the future to add a digital update \ (tot \) array.

So that we can \ (O (1) \) to answer each query a.

Segment tree (subtasks 2,3):

To take into account the interval \ ([L, R] \ ) is added after the number \ (X \) Update \ (TOT \) process is actually an array of a matrix multiplication \ (tot \ times M_x \) process.

For example, when \ (K = 5 \) when the \ (TOT \) after adding a \ (3 \) of the process is equivalent to:
\ [M3 = \ the begin {bmatrix}. 1 & 0 & 0 &. 1 & 0 \\ 0 &. 1 & 0 &. 1 & 0 \\ 0 & 0 &. 1 &. 1 & 0 \\ 0 & 0 & 0 & 2 & 0 \\ 0 & 0 & 0 & 0 & 1 \ end {bmatrix} \]

满足
\[ [c_0\ \ c_1\ \ c_2\ \ c_3 \ \ c_4]\cdot M_3=[c_0\ \ c_1\ \ c_2\ \ c_0+c_1+c_2+2c_3 \ \ c_4] \]

In other words corresponding to the next to add a 3 \ (C_3 \) increased \ (c_0 + c_1 + c_2 + c_3 \)

This matrix multiplication inspire us to deal with the tree line interval.

If a node represents \ ([L, R & lt] \) , then it should be represented by a matrix \ (M = M_ {A_L} \ times \ cdots \ times M_ {A_R} \)

So that we can \ (O (NK ^ 3) \) achievements, a single query \ (O (K ^ 3 \ log N) \) to get rid of.

The total complexity is \ (O ((N + Q \ log N) K ^ 3) \) , and can not afford too large probability Subtask2.

We can optimize the contribution to the process queries.

  • For inquiries, we only need to know the results of the first row of the matrix product. So we only have to deal \ (1 \ times K \) matrix and \ (K \ times K \) matrix multiplication, so a single query complexity becomes \ (O (K ^ 2 \ log N) \) , so that you can live off the subtask2.

  • For the achievements, we each \ (K \) matrix tied up as a matrix (similar to the block?) Then after binding matrix we built a tree line. Then for each query matrix product we bundled into the digital and fragmented. For the fragmented digital Subtask1 we follow the same violence \ (O (K) \) to add a number. The complexity of this inquiry will not be affected. Such overall complexity is \ (O (\ dfrac {N } {K} K ^ 3 + QK ^ 2logN) \)

After optimization can live subtask3, you can even get all the points.

Divide and Conquer (out of practice)

Segment tree approach can also be modified, but it is not necessary to use the tree line.

In fact, given \ (b_1, b_2, \ ldots , b_N \) and a \ (O (1) \) operation \ (\ Oplus \) , \ (Q \) queries \ (\ bigoplus \ limits_ { Rb_i L} = ^ I \) , we can ask offline down, shared equally \ (O (1) \) answer.

Specifically, we put every interval \ ([L, R] \ ) is divided into \ ([L, M] \ ) and \ ([M +. 1, R & lt] \) , all pretreated \ ([I , M] \) , \ ([M +. 1, I] \) interval answer, then across to \ (M \) interval \ ([L, R & lt] \) , we \ ([l, M ] \) and \ ([M + 1, r ] \) be merged. For the rest does not cross \ (M \) range, we can recursive processing.

In this question, we can simultaneously process comprising the \ (M \) and \ (M + 1 \) interval. We assume that the sub-sequence is the subscript \ (j_1 <J_2 <\ ldots <j_a \ Le M <J_. 1 + {A} <\ ldots <j_x \) . We enumerate \ (A_ {j_a} \) value, generating all legal \ ([i, M] \ ) and \ ([M + 1, i ] \) interval answer. Such complexity is \ (O (NK ^ 2) \) a. For a \ ([l, r] \ ) inquiry, we \ (O (K) \) time combined \ ([l, M] \ ) and \ ([M + 1, r ] \) to . The remaining inquiries recursion process can be.

<Note 1> add, specifically generate all legal \ ([i, M] \ ) and \ ([M + 1, i ] \) sub-sequence number is this:

  1. For the left half of the interval \ ([L, M] \) , \ (LANs [I] [J] \) represents the \ ([i, M] \ ) in the number of digital \ (J \) at the end is not down sequence.

    As official positive solutions in the code segment

    void countLeft(int a,int b)
    {
     for(int i=a;i<=b;i++)
         for(int k=1;k<=K;k++)
             lans[i][k] = 0;
     for(int k=K;k>=1;k--)
     {
         for(int j=k;j<=K;j++)
             cnt[j] = 0;
         for(int i=b;i>=a;i--)
         {
             if(A[i] == k)
             {
                 cnt[k] = msum(2*cnt[k] + 1);
                 for(int j=k+1;j<=K;j++)
                     cnt[j] = msum(msum(2*cnt[j]) + lans[i][j]);
             }
             for(int j=k;j<=K;j++)
                 lans[i][j] = msum(lans[i][j] + cnt[j]);
         }
     }
    }

    Let's enumerate \ (k \) , means that we currently consider to \ ([k, K] \ ) did not fall at the end of the sequence. Then we press the \ (M \) to \ (L \) sequence enumerate the current position, \ (CNT [J] \) represents the current position to the \ (M \) in the number of subsequences to \ (K \) and beginning with \ (j \) at the end. Obviously \ (lans [i] [j ] \) is a different enumeration \ (K \) when the position \ (I \) when \ (cnt [j] \) accumulation.

  2. Similarly, when considering the right half of the interval \ (rans [i] [j ] \) represents \ ([M + 1, i ] \) in the number of non-drop sequence j at the beginning, but considering that we enumerate is \ (A_ {j_a} \) values, we \ (rans [i] [j ] \) to make and a prefix, let represent \ ([M + 1, i ] \) in the number of to nondecreasing sequence number is greater than the beginning of j.

Government How to correct

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#define MAXN 200000
#define MAXQ 200000
#define MOD 1000000007

int msum(int a)
{
  if(a >= MOD) return a-MOD;
  return a;
}


int N,K,Q;
int A[MAXN];
int l[MAXQ], r[MAXQ];
int qid[MAXQ];
int qans[MAXQ];

int lans[MAXN][21];
int rans[MAXN][21];
int cnt[21];

void countLeft(int a,int b)
{
  for(int i=a;i<=b;i++)
      for(int k=1;k<=K;k++)
          lans[i][k] = 0;
  for(int k=K;k>=1;k--)
  {
      for(int j=k;j<=K;j++)
          cnt[j] = 0;
      for(int i=b;i>=a;i--)
      {
          if(A[i] == k)
          {
              cnt[k] = msum(2*cnt[k] + 1);
              for(int j=k+1;j<=K;j++)
                  cnt[j] = msum(msum(2*cnt[j]) + lans[i][j]);
          }
          for(int j=k;j<=K;j++)
              lans[i][j] = msum(lans[i][j] + cnt[j]);
      }
  }
}

void countRight(int a,int b)
{
  for(int i=a;i<=b;i++)
      for(int k=1;k<=K;k++)
          rans[i][k] = 0;
  for(int k=1;k<=K;k++)
  {
      for(int j=1;j<=k;j++)
          cnt[j] = 0;
      for(int i=a;i<=b;i++)
      {
          if(A[i] == k)
          {
              cnt[k] = msum(2*cnt[k] + 1);
              for(int j=1;j<k;j++)
                  cnt[j] = msum(msum(2*cnt[j]) + rans[i][j]);
          }
          for(int j=1;j<=k;j++)
              rans[i][j] = msum(rans[i][j] + cnt[j]);
      }
  }
}

int split(int qa,int qb, int m)
{
  int i = qa;
  int j = qb;
  while(i<j)
  {
      if(r[qid[i]] > m && r[qid[j]] <= m)
      {
          swap(qid[i],qid[j]);
          i++, j--;
      }
      else if(r[qid[i]] > m)
          j--;
      else if(r[qid[j]] <= m)
          i++;
      else
          i++, j--;
  }
  if(i > j) return j;
  else if(r[qid[i]] <= m) return i;
  else return i-1;
}

void solve(int a,int b,int qa,int qb)
{
  if(a>b || qa>qb) return;
  if(a == b)
  {
      for(int i=qa;i<=qb;i++)
          qans[qid[i]] = 1;
      return;
  }
  int m = (a+b)/2;
  countLeft(a,m);
  countRight(m+1,b);
  for(int i=m+1;i<=b;i++)
      for(int k=K-1;k>=1;k--)
          rans[i][k] = msum(rans[i][k] + rans[i][k+1]);
  int qDone = 0;
  for(int i=qa;i<=qb;i++)
  {
      int q = qid[i];
      if(r[q] > m && l[q] <= m)
      {
          qans[q] = 0;
          for(int k=1;k<=K;k++)
              qans[q] = msum(qans[q] + (lans[l[q]][k]*((long long)rans[r[q]][k]))%MOD);
          for(int k=1;k<=K;k++)
              qans[q] = msum(qans[q] + lans[l[q]][k]);
          qans[q] = msum(qans[q] + rans[r[q]][1]);
          qDone++;
      }
      else if(qDone>0)
          qid[i-qDone] = qid[i];
  }
  qb -= qDone;
  int qm = split(qa,qb,m);
  solve(a,m,qa,qm);
  solve(m+1,b,qm+1,qb);
}

int main()
{
  freopen("nondec.in","r",stdin);
  freopen("nondec.out","w",stdout);
  cin >> N >> K;
  for(int i=0;i<N;i++)
      cin >> A[i];
  cin >> Q;
  for(int i=0;i<Q;i++)
  {
      cin >> l[i] >> r[i];
      l[i]--,r[i]--;
      qid[i] = i;
  }
  solve(0,N-1,0,Q-1);
  for(int i=0;i<Q;i++)
      cout << qans[i]+1 << '\n';
}

My code:

#include<bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define fi first
#define se second

#define y0 pmt
#define y1 pmtpmt
#define x0 pmtQAQ
#define x1 pmtQwQ

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int > vi;
typedef pair<int ,int > pii;
const int INF=0x3f3f3f3f, maxn=200007;
const int MOD=1e9+7;
const ll LINF=0x3f3f3f3f3f3f3f3fLL;
const ll P=19260817;
char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline ll read(){
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=((x<<3)+(x<<1)+ch-'0')%MOD,ch=getchar();
    return x*f;
}
void write(int x){
    if(!x)putchar('0');if(x<0)x=-x,putchar('-');
    static int sta[20];register int tot=0;
    while(x)sta[tot++]=x%10,x/=10;
    while(tot)putchar(sta[--tot]+48);
}
int n,K,Q;
struct Query{
    int l,r,id;
}q[maxn],q1[maxn],q2[maxn];
// int len1,len2;
int a[maxn];
int cnt[27];
int lans[maxn][27],rans[maxn][27];
int ans[maxn];
int mod1(int a){return a>MOD?a-MOD:a;}
void left(int l,int r){
    for(int i=l;i<=r;i++)
        for(int j=1;j<=K;j++)lans[i][j]=0;
    for(int k=K;k>=1;k--){
        for(int j=k;j<=K;j++)cnt[j]=0;
        for(int i=r;i>=l;i--){
            if(a[i]==k){
                cnt[k]=mod1(mod1(cnt[k]*2)+1);
                for(int j=k+1;j<=K;j++)cnt[j]=mod1(mod1(cnt[j]*2)+lans[i][j]);
            }
            for(int j=k;j<=K;j++)lans[i][j]=mod1(lans[i][j]+cnt[j]);
        }
    }
}
void right(int l,int r){
    for(int i=l;i<=r;i++)
        for(int j=1;j<=K;j++)rans[i][j]=0;
    for(int k=1;k<=K;k++){
        for(int j=1;j<=k;j++)cnt[j]=0;
        for(int i=l;i<=r;i++){
            if(a[i]==k){
                cnt[k]=mod1(mod1(cnt[k]<<1)+1);
                for(int j=1;j<k;j++)cnt[j]=mod1(mod1(cnt[j]<<1)+rans[i][j]);
            }
            for(int j=1;j<=k;j++)rans[i][j]=mod1(rans[i][j]+cnt[j]);
        }
    }
    for(int i=l;i<=r;i++)
        for(int k=K-1;k>=1;k--)
            rans[i][k]=mod1(rans[i][k]+rans[i][k+1]);
}
void solve(int l,int r,int ql,int qr){
    if(l>r||ql>qr)return ;
    if(l==r){
        for(int i=ql;i<=qr;i++){
            ans[q[i].id]=1;
        }
        return ;
    }
    int mid=(l+r)>>1;
    left(l,mid);right(mid+1,r);
    int len1=0,len2=0;
    for(int i=ql;i<=qr;i++){
        if(q[i].r<=mid)q1[++len1]=q[i];
        else if(q[i].l>mid)q2[++len2]=q[i];
        else {
            for(int k=1;k<=K;k++)ans[q[i].id]=mod1(ans[q[i].id]+1ll*lans[q[i].l][k]*rans[q[i].r][k]%MOD);
            for(int k=1;k<=K;k++)ans[q[i].id]=mod1(ans[q[i].id]+lans[q[i].l][k]);
            ans[q[i].id]=mod1(ans[q[i].id]+rans[q[i].r][1]);
        }
    }
    for(int i=ql;i<ql+len1;i++)q[i]=q1[i-ql+1];
    for(int i=ql+len1;i<ql+len1+len2;i++)q[i]=q2[i-ql-len1+1];
    solve(l,mid,ql,ql+len1-1);
    solve(mid+1,r,ql+len1,ql+len1+len2-1);

}
int main(){
    scanf("%d%d",&n,&K);
    for(int i=1;i<=n;i++)scanf("%d",a+i);
    scanf("%d",&Q);
    for(int i=1;i<=Q;i++)
        scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
    solve(1,n,1,Q);
    for(int i=1;i<=Q;i++)printf("%d\n",mod1(ans[i]+1));
    return 0;
}

Complexity is \ (O (NK ^ 2 \ log N + Q (K + \ log N)) \) of

Matrix inversion (out of practice)

Order \ (ipref [x] = M_ {A_ {x-1}} ^ {- 1} \ cdot M_ {A_ {x-2}} ^ {- 1} \ cdots M_ {A_1} ^ {- 1} \ ) , and \ (Pref [X] = of M_ {A_1} \ CDOT of M_ {A_2} \ cdots of M_ {A_ {X-. 1}} \) , calculated \ ([m_x ^ {- 1 }] \) is actually quite easy .

When, for example, \ (K = 5 \) when,
\ [^ {M_3 -. 1} = \ bmatrix the begin {0} & 0. 1 & & & -½ 0. 1 & 0 \\ 0 & & & -½ 0 \\ 0 & 0 & 1 &
-1/2 & 0 \\ 0 & 0 & 0 & 1/2 & 0 \\ 0 & 0 & 0 & 0 & 1 \\ \ end {bmatrix}, \] satisfies
\ [\ begin {bmatrix} c_0 & c_1 & c_2 & c_0 + c_1 + c_2 + 2c_3 & c_4 \ end {bmatrix} \ cdot M_3 ^ {- 1} = \ begin {bmatrix} c_0 & c_1 & c_2 & c_3 & c_4 . \ end {bmatrix} \]
so and because \ (m_x \) and \ (m_x ^ {- 1} \) and like matrix, we can use multiplication distribution rate \ (O (NK ^ 2) \) processing time within the \ (Pref, IPref \) .

Then \ ([L, R] \ ) answer \ (A_L, \ ldots, A_R \) does not actually fall sequence number \ (\ sum \ limits_ {i = 0} ^ {K-1} (ipref [. 1-L] \ CDOT Pref [R & lt]) [0] [I] \) , it is the complexity of a single \ (O (K ^ 2) \) a.

Considering the first row of the product matrix we only need to answer can be rewritten as \ (\ sum \ limits_ {i = 0} ^ {K-1} (ipref [L-1] [0] \ cdot pref [R]) [i] \\ = \ sum_ { i = 0} ^ {K-1} (ipref [L-1] [0] [i] \ cdot \ left (\ sum_ {j = 0} ^ {K-1} pref [R] [i] [ j] \ right)). \)

\ ((\ sum_ {j = 0} ^ {K-1} pref [R] [i] [j]) \) obviously be pretreated, then gone.

Complexity is \ (O (NK ^ 2 + QK) \) a.

Official sol:

#include <bits/stdc++.h>
using namespace std;
 
typedef long long ll;
const int MOD = 1e9+7; // 998244353; // = (119<<23)+1
const int MX = 5e4+5; 

void setIO(string name) {
    ios_base::sync_with_stdio(0); cin.tie(0);
    freopen((name+".in").c_str(),"r",stdin);
    freopen((name+".out").c_str(),"w",stdout);
}
 
struct mi {
    int v; explicit operator int() const { return v; }
    mi(ll _v) : v(_v%MOD) { v += (v<0)*MOD; }
    mi() : mi(0) {}
};
mi operator+(mi a, mi b) { return mi(a.v+b.v); }
mi operator-(mi a, mi b) { return mi(a.v-b.v); }
mi operator*(mi a, mi b) { return mi((ll)a.v*b.v); }
typedef array<array<mi,20>,20> T;
 
int N,K,Q;
vector<int> A;
array<mi,20> sto[MX], isto[MX];
mi i2 = (MOD+1)/2;
 
void prin(T& t) { // print a matrix for debug purposes
    for (int i = 0; i < K; ++i) {
        for (int j = 0; j < K; ++j) 
            cout << t[i][j].v << ' ';
        cout << "\n";
    }
    cout << "-------\n";
}
 
int main() {
    setIO("nondec");
    cin >> N >> K; A.resize(N); 
    for (int i = 0; i < N; ++i) cin >> A[i];
    T STO, ISTO;
    for (int i = 0; i < K; ++i) 
        STO[i][i] = ISTO[i][i] = 1;
    for (int i = 0; i <= N; ++i) {
        for (int j = 0; j < K; ++j) 
            for (int k = j; k < K; ++k) 
                sto[i][j] = sto[i][j]+STO[j][k];
        for (int k = 0; k < K; ++k) 
            isto[i][k] = ISTO[0][k];
        if (i == N) break;
        int x = A[i]-1;
        // STO goes from pre[i] to pre[i+1]
        // set STO = STO*M_{A[i]}
        for (int j = 0; j <= x; ++j) 
            for (int k = x; k >= j; --k) 
                STO[j][x] = STO[j][x]+STO[j][k];
        // ISTO goes from ipre[i] to ipre[i+1]
        // set ISTO=M_{A[i]}^{-1}*ISTO
        for (int j = 0; j < x; ++j) 
            for (int k = x; k < K; ++k)
                ISTO[j][k] = ISTO[j][k]-i2*ISTO[x][k];
        for (int k = x; k < K; ++k) 
            ISTO[x][k] = ISTO[x][k]*i2;
    }
    cin >> Q;
    for (int i = 0; i < Q; ++i) {
        int L,R; cin >> L >> R;
        mi ans = 0; 
        for (int j = 0; j < K; ++j) 
            ans = ans+isto[L-1][j]*sto[R][j];
        cout << ans.v << "\n";
    }
}

I do not write / kk;

Guess you like

Origin www.cnblogs.com/pmt2018/p/12239401.html