11.24 考试

T4
求最长不下降子序列,因为最大值为150,并且数据产生方式有循环;
所以可以找规律,在后面的时候,每经过一个循环节答案最大值+1;
恶心的事循环节前面和后面的处理,很难调;

#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;
const int N=1e5+7;
LL n,tt,ans;
int t0,A,B,C,D,ff=0;
int vis[N],a[N],last[N];
LL f[N];
int main(){
	freopen("lis.in","r",stdin);
	freopen("lis.out","w",stdout);
	scanf("%lld",&n);
	scanf("%d%d%d%d%d",&t0,&A,&B,&C,&D);
	a[1]=t0;
	vis[a[1]]=1;
	last[a[1]]=1;
//	cout<<a[1]<<" ";
	for(int i=2;i<=n;i++){
		a[i]=1LL*(1LL*a[i-1]*a[i-1]*A+B*a[i-1]+C)%D;
		tt=i;
//		cout<<a[i]<<" ";
		if(vis[a[i]]){
			ff=1;
			break;
		}
		vis[a[i]]=1;
		last[a[i]]=i;
//		if(a[i]==9) cout<<"------"<<i<<" ";
	}
//	cout<<"\n";
//	cout<<tt<<"\n";
//	cout<<a[tt]<<"\n";
	LL l=last[a[tt]];
//	cout<<l<<"\n";
	if(ff==1) tt--;
	LL uu=tt-l+1;
//	cout<<uu<<"\n";
//	cout<<l<<" "<<"\n";
	LL ss=l-1+100*uu;
	for(int i=1;i<=min(ss,n);i++){
		if(i>tt) a[i]=1LL*(1LL*a[i-1]*a[i-1]*A+B*a[i-1]+C)%D;
		LL maxn=0;
		for(int j=1;j<i;j++){
			if(a[j]<=a[i]){
				maxn=max(maxn,f[j]);
			}
		}
		f[i]=maxn+1;
//		cout<<f[i]<<" ";
	}
	if(ff==0||ss>=n){
		memset(f,0,sizeof(f));
		for(int i=1;i<=n;i++){
			if(i>tt) a[i]=1LL*(1LL*a[i-1]*a[i-1]*A+B*a[i-1]+C)%D;
			LL maxn=0;
			for(int j=1;j<i;j++){
				if(a[j]<=a[i]){
					maxn=max(maxn,f[j]);
				}
			}
			f[i]=maxn+1;
//			ans=max(ans,f[i]);
		}
		for(int i=1;i<=n;i++){
			ans=max(ans,f[i]);
		}
		cout<<ans;
		return 0;
	}
//	cout<<ss<<"\n";
	LL kk=n-ss;
//	cout<<kk<<"\n";
	LL oo=kk/uu;
	LL pp=0;
//	cout<<"--"<<oo<<"\n";
	if(oo!=0){
		oo--;
		pp=uu;
	}
//	cout<<(uu*99+l)<<"\n";
	for(int i=(uu*99+l);i<=ss;i++){
//		LL zz=(i-(l-1))/uu;
//		if((i-(l-1))%uu==0) zz--;
		f[i]+=oo;
//		cout<<f[i]<<" ";
	}
//	cout<<"\n";
//	cout<<f[1]<<"\n";
	LL yy=kk%uu;
//	cout<<yy<<"\n";
	pp+=yy;
//	cout<<pp<<"\n";
	for(int i=ss+1;i<=ss+pp;i++){
		if(i>ss) a[i]=1LL*(1LL*a[i-1]*a[i-1]*A+B*a[i-1]+C)%D;
		LL maxn=0;
		for(int j=1;j<i;j++){
			if(a[j]<=a[i]){
				maxn=max(maxn,f[j]);
			}
		}
		f[i]=maxn+1;
	}
	for(int i=1;i<=ss+pp;i++){
		ans=max(ans,f[i]);
	}
	cout<<ans;
	fclose(stdin);
	fclose(stdout);
	return 0; 
}
/*
309
126 139 23 135 26

707
77 56 129 57 131

10
1 1 3 5 37

1991
128 128 73 113 75

532889960237
143 88 122 1 147

1329
30 104 50 130 136
*/

T2
给定一个数组,可以选两个数a,b;
把a和b合并起来,就是a在前,b在后产生的一个新数;
问有多少种选的方案,使得拼起来的数不是k的倍数;

虑求有多少对(i; j)满足拼数结果为k的倍数。可以发现,对x; y拼数
的本质是x*10⌊log10y⌋+1+y(这个式子不严谨,明白意思就行)。只要加号
左边的与加号右边的对k取余的数能够加起来得到k或0即可。考虑
枚举j,设j的位数为dig=⌊log10aj⌋+ 1,那么只要查询有多少个数满足乘10dig的结果对k取余为k

#include<iostream>
#include<cstdio>
#include<map>
#define LL long long
using namespace std;
const int N=2e5+7;
int n,maxn;
LL k,ans;
LL a[N];
map<int,int> S[11];
int get(int x){
	int res=0;
	while(x!=0){
		res++;
		x/=10;
	}
	return res;
}
int main(){
	freopen("piece.in","r",stdin);
	freopen("piece.out","w",stdout);
	scanf("%d%lld",&n,&k);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		maxn=max(maxn,get(a[i]));
	}
	for(int i=1;i<=n;i++){
		int tt=a[i];
		for(int j=1;j<=maxn;j++){
			tt=1LL*tt*10%k;
			S[j][tt]++;
		}
	}
	for(int i=1;i<=n;i++){
		int tt=a[i];
		int nod=get(a[i]);
		for(int j=1;j<=nod;j++) tt=1LL*tt*10%k;
		S[nod][tt]--;
		if(a[i]%k){
			ans+=S[nod][k-a[i]%k];
		}else{
			ans+=S[nod][0];
		}
		S[nod][tt]++;
	}
	cout<<1LL*n*(n-1)-ans;
	fclose(stdin);
	fclose(stdout);
	return 0;
}
/*
4 11
45 1 10 12
*/

上一篇:zTree实现基本树


下一篇:一些基础的东西