Codeforces 582B Once Again

时间:2023-03-08 16:57:48
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[][];
int n;
public:
mx<T>(int _n):n(_n){}
mx<T>():n(){}
};
int n,T,b[];
int read(){
int t=,f=;char ch=getchar();
while (ch<''||ch>''){if (ch=='-') f=-;ch=getchar();}
while (''<=ch&&ch<=''){t=t*+ch-'';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=;i<=a.n;i++)
for (int j=;j<=a.n;j++)
c.r[i][j]=-;
for (int i=;i<=a.n;i++)
for (int j=;j<=a.n;j++)
for (int k=;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=;i<=n;i++)
for (int j=;j<=n;j++)
a.r[i][j]=c.r[i][j]=;
for (int i=;i<=n;i++) b[i]=read();
for (int i=;i<=n;i++)
for (int j=;j<=n;j++)
if (b[i]<=b[j]) {
a.r[i][j]=;
for (int k=;k<j;k++)
if (b[k]<=b[j])
a.r[i][j]=std::max(a.r[i][j],a.r[i][k]+);
}else a.r[i][j]=-;
a.n=n;
c.n=n;
while (T){
if (T%) c=c*a;
T/=;
a=a*a;
}
int ans=;
for (int i=;i<=n;i++)
for (int j=;j<=n;j++)
ans=std::max(ans,c.r[i][j]);
printf("%d\n",ans);
return ;
}