2022/8/16 总结

A.数字

  • 第一眼以为是数论,第二眼是 \(\mathtt{DP}\)

  • 本题又名卡常技术综合运用,如何将 30s 的大样例卡进 10s

Solution

  • \(\mathtt{DP+BitSet}\)

  • 如果直接 \(\mathtt{DP}\),时间复杂度最坏会到 \(10^{10}\),肯定过不了。这时就需要请出我们的 \(\mathtt{BitSet}\)了;

  • 开一个 \(\mathtt{BitSet}\) 数组,用每一个二进制位的 \(0/1\) 来表示这个位数表示的数字能否凑出,加法用 \(\mathtt{<<}\) 可以直接解决,复杂度将原来值域的 \(10^6\) 这一层大大优化;

AC code
#include<bits/stdc++.h>
using namespace std;

inline int read(){
	int s=0,f=1;
	char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		s=s*10+int(ch-'0');
		ch=getchar();
	}
	return s*f;
}

const int N=105;
const int M=1e6+10;

#define re register

int n;
bitset<M>f[N];

int main(){
	freopen("number.in","r",stdin);
//	freopen("number.out","w",stdout);
	n=read();
	int a,b;
	f[0].set(0);
	for(int i=1;i<=n;++i){
		a=read(),b=read();
		for(int j=a;j<=b;++j)
			f[i]|=f[i-1]<<(j*j);
	}
	printf("%d",f[n].count());
	return 0;
}

BitSet

BitSet 操作一览
const int N=1e5+10;

bitset<N>b;

bool s=b.any();//如果 b 中存在为 1 的位,返回 true
bool f=b.none();//如果 b 中不存在为 1 的位,返回 true
int num=b.count();//返回 b 中为 1 的位数

b.set(x);//把 b 的第 x 位设置为1
b[x]=1;//同上
bool xs=b.test(x);//求 b 的第 x 位是否为 1,也可以下标访问
b.reset(x);//把 b 的第 x 位设置为 0,也可以下标访问

b.flip(x);//翻转第 x 位
b[x].flip();//也是翻转第 x 位
b.flip();//翻转所有的位的值

B.数列递推

  • 又是半道结论题……(确信了,我确实和结论题有仇);

Solution

  • 根据递推式 \(a_i=k\times a_{i-1}+a_{i-2}(k>0)\),容易得到一个结论:

    • 如果 \(a_{i-1},a_{i-2}>0\),那么从这之后的数列单调递增;
    • 如果 \(a_{i-1},a_{i-2}<0\),那么从这之后的数列单调递减;
    • 如果 \(a_0=a_1=0\),那么整个数列全部为 \(0\),直接输出 \(s_1\) 即可;
  • 根据题解,可以证明暴力求出 \(a_{i-1}\)\(a_{i-2}\) 同号的复杂度在 \(\log \log\) 级别(虽然我也不知道它是怎么证的),所以可以直接暴力递推,直到 \(a_{i-1}\)\(a_{i-2}\) 同号;

  • 但需要注意的是,即使推到同号,也需要考虑前面是否存在比 \(s_m\) 更大/小的 \(s_i\)

AC code
#include<bits/stdc++.h>
using namespace std;

inline int read(){
	int s=0,f=1;
	char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		s=s*10+int(ch-'0');
		ch=getchar();
	}
	return s*f;
}

#define ll long long

const int N=1e5+10;
const ll Inf=1ll*1<<62;

int n,m;
int s[N],p;
int pos1,pos2,tg;
ll f[N<<5],mx,mn;

void dfs(int k,int id){
	if(id>s[m]) return ;
	f[id]=1ll*k*f[id-1]+f[id-2];
//	cout<<id<<" "<<f[id]<<endl;
	if(1ll*f[id]*f[id-1]>0 && !tg){
		if(f[id]>0)
			tg=1;
		else tg=2;
	}
	if(s[p]==id){
		if(f[id]>mx)
			mx=f[id],pos1=id;
		if(f[id]<mn)
			mn=f[id],pos2=id;
		++p;
	}
	if(tg==1 && f[id]>=mx && id<=s[m]){
		if(f[id]>mx || id<s[m]){
			pos1=s[m];
			if(pos2==-1)
				pos2=s[1];
			return ;
		}
	}
	else if(tg==2 && f[id]<=mn && id<=s[m]){
		if(!(f[id]==mn && id==s[m])){
			pos2=s[m];
			if(pos1==-1)
				pos1=s[1];
			return ;
		}
	}
	dfs(k,id+1);
	return ;
}

int main(){
//	freopen("sequence.in","r",stdin);
//	freopen("sequence.out","w",stdout);
	m=read();
	for(int i=1;i<=m;++i)
		s[i]=read();
	n=read();
	ll a0,a1,k;
	for(int i=1;i<=n;++i){
		a0=read(),a1=read(),k=read();
		if(a1==0 && a0==0){
			printf("%d %d\n",s[1],s[1]);
			continue;
		}
		p=1;
		pos1=pos2=-1;
		mx=-Inf,mn=Inf;
		f[0]=a0,f[1]=a1;
		while(s[p]<2){
			if(f[s[p]]>mx)
				mx=f[s[p]],pos1=s[p];
			if(f[s[p]]<mn)
				mn=f[s[p]],pos2=s[p];
			++p;
		}
		tg=0;
		dfs(k,2);
		printf("%d %d\n",pos1,pos2);
	}
	return 0;
}
posted @ 2022-08-16 20:23  Star_LIcsAy  阅读(48)  评论(0)    收藏  举报