题解 最长不下降子序列

传送门

切记 不膜D一定会爆零 一定要膜D! 题里输入很毒瘤,不要膜错了,看清楚,是膜大D!

打个表可以发现有循环节
带循环节的LIS不太好处理,可以考虑\(n^2\)DP的时候给它带个权
然而没这么简单,在进入循环前可以有几个循环节不按其它循环节的选法被选择
举个例子,循环节是 56132 ,正常情况下我们只能从这里面选一个数
但我们把它写开, 56132 56132 56132 56132 是一组更优解
题解利用矩阵乘法魔改取max也具有结合律搞成了矩阵快速幂,然而我没学会
可以证明,这样的情况最多影响逆序对个数个循环节,所以我直接复制了一百个循环节放在前后水过去了
其实应该放150个,但我求LIS是\(n^2\)的所以放那么多会T,而且数据比较水放20个就能A,所以……

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define ll long long 
#define int long long 

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, t0, a, b, c, d;
int s[N];

namespace force{
	int v[N], top;
	void solve() {
		s[1]=t0;
		for (int i=2; i<=n; ++i) s[i]=(a*s[i-1]*s[i-1]+b*s[i-1]+c)%d;
		//cout<<"s: "; for (int i=1; i<=n; ++i) cout<<s[i]<<' '; cout<<endl;
		for (int i=1; i<=n; ++i) {
			if (!top || v[top]<=s[i]) v[++top]=s[i];
			else *upper_bound(v+1, v+top+1, s[i])=s[i];
		}
		printf("%lld\n", top);
		//cout<<"top: "<<top<<endl;
		//for (int i=1; i<=top; ++i) cout<<v[i]<<' '; cout<<endl;
	}
}

namespace task1{
	int v[N], top;
	void solve() {
		s[1]=t0;
		for (int i=2; i<=min(n, 1000ll); ++i) s[i]=(a*s[i-1]*s[i-1]+b*s[i-1]+c)%d;
		//cout<<"s: "; for (int i=1; i<=n; ++i) cout<<s[i]<<' '; cout<<endl;
		for (int i=1; i<=min(n, 1000ll); ++i) {
			if (!top || v[top]<=s[i]) v[++top]=s[i];
			else *upper_bound(v+1, v+top+1, s[i])=s[i];
		}
		printf("%lld\n", top);
		//cout<<"top: "<<top<<endl;
		//for (int i=1; i<=top; ++i) cout<<v[i]<<' '; cout<<endl;
	}
}

namespace task2{
	int dp[N];
	int num[N][2], s2[N];
	int sta[N], top;
	//bool vis[N];
	unordered_map<ll, bool> vis;
	void solve() {
		s[1]=t0;
		for (int i=2; i<=5000; ++i) s[i]=(a*s[i-1]*s[i-1]+b*s[i-1]+c)%d;
		//cout<<"s: "; for (int i=1; i<=1000; ++i) cout<<s[i]<<' '; cout<<endl;
		for (int i=2000; i<=5000; ++i) {
			if (!vis[s[i]]) vis[s[i]]=1, sta[++top]=s[i];
			else break;
		}
		int pos=1;
		while (s[pos]!=sta[1]) num[pos][0]=s[pos], num[pos][1]=1, ++pos;
		//cout<<"info: "<<n<<' '<<pos<<' '<<top<<endl;
		int t=(n-pos+1)/top-200;
		//cout<<"t: "<<t<<endl;
		for (int j=1; j<=100; ++j) 
			for (int i=1; i<=top; ++i) num[pos][0]=sta[i], num[pos][1]=1, ++pos;
		for (int i=1; i<=top; ++i) num[pos][0]=sta[i], num[pos][1]=t, ++pos;
		for (int j=1; j<=100; ++j) 
			for (int i=1; i<=top; ++i) num[pos][0]=sta[i], num[pos][1]=1, ++pos;
		for (int i=1,bkp=pos; i<=(n-bkp+1)%top; ++i) num[pos][0]=sta[i], num[pos][1]=1, ++pos;
		--pos;
		
		#ifdef DEBUG
		cout<<"sta: "; for (int i=1; i<=top; ++i) cout<<sta[i]<<' '; cout<<endl;
		cout<<"pos: "; for (int i=1; i<=pos; ++i) cout<<setw(5)<<num[i][0]<<' '; cout<<endl;
		cout<<"pos: "; for (int i=1; i<=pos; ++i) cout<<setw(5)<<num[i][1]<<' '; cout<<endl;
		#endif
		
		for (int i=1; i<=pos; ++i) {
			dp[i]=num[i][1];
			for (int j=1; j<i; ++j) {
				if (num[j][0]<=num[i][0] && (num[j][1]==1||num[i][1]==1)) 
					dp[i]=max(dp[i], dp[j]+num[i][1]);
			}
		}
		int ans=0;
		for (int i=1; i<=pos; ++i) ans=max(ans, dp[i]);
		printf("%lld\n", ans);
		exit(0);
	}
}

signed main()
{
	n=read(); t0=read(); a=read(); b=read(); c=read(); d=read();
	if (n<N) force::solve();
	else task2::solve();
	
	return 0;
}
posted @ 2021-08-03 20:39  Administrator-09  阅读(17)  评论(0编辑  收藏  举报