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;
}

浙公网安备 33010602011771号