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\n",ans); return 0; }