Codeforces 582B Once Again

http://codeforces.com/contest/582/problem/B

题目大意:给出一个序列,是由一个长度为n的序列复制T次得到的,问最长非下降子序列的长度。

思路:我们建立一个n*n的矩阵,a[i][j]代表第一段以i为末尾,第二段以j为末尾,拼接起来能增加多少长度,这样只要有一个空的矩阵c,我们让c乘上a^t,记住,这里的乘里面是:c[i][j]=max(c[i][j],a[i][k]*b[k][j]),略微和其他的矩乘不同。然后c里面元素最大那个就是答案。

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<iostream>
template<typename T>
class mx {
public:
    T r[155][155];
    int n;
public:
    mx<T>(int _n):n(_n){}
    mx<T>():n(0){}
};
int n,T,b[200005];
int read(){
    int t=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
   return t*f;
}
template<typename T>
mx<T> operator *(mx<T> a,mx<T> b){
    mx<T> c;
    c.n=a.n;
    for (int i=1;i<=a.n;i++)
     for (int j=1;j<=a.n;j++)
      c.r[i][j]=-99999999;
    for (int i=1;i<=a.n;i++)
     for (int j=1;j<=a.n;j++)
     for (int k=1;k<=a.n;k++)
       c.r[i][j]=std::max(c.r[i][j],a.r[i][k]+b.r[k][j]);
    return c;    
}
int main(){
    n=read();T=read();
    for (int i=1;i<=n;i++)
     for (int j=1;j<=n;j++)
      a.r[i][j]=c.r[i][j]=0;
    for (int i=1;i<=n;i++) b[i]=read();
    for (int i=1;i<=n;i++)
     for (int j=1;j<=n;j++)
        if (b[i]<=b[j]) {
            a.r[i][j]=1;
            for (int k=1;k<j;k++)
             if (b[k]<=b[j])
              a.r[i][j]=std::max(a.r[i][j],a.r[i][k]+1);
        }else a.r[i][j]=-99999999;
   a.n=n;
    c.n=n;
   while (T){
        if (T%2) c=c*a;
        T/=2;
        a=a*a;
    }
    int ans=0;
    for (int i=1;i<=n;i++)
     for (int j=1;j<=n;j++)
      ans=std::max(ans,c.r[i][j]);
    printf("%d
",ans);  
    return 0;
}
 
原文地址:https://www.cnblogs.com/qzqzgfy/p/5624683.html