刷点经典题,难题固然要看,但蓝桥杯偏基础。
知识点:记忆化搜索
1、这题中,高和矮是相对概念,对称,所以除了1这个特判,其他dfs一次然后乘二即可。
2、从0位,或从第n位开始都一样,但要注意的是,你从第0位,而且最小值选的不是0,而是-1时,会出现dp[0][-1][0]的情况,这涉及C++的变量的基本存储情况,它不会初始化为-1,而是变成sum,或cnt,或其他的值,其他初始为0,所以你如果照我下面代码遍历时改成dfs(0,-1,0),结果始终为0.
3.也可以用排列组合做。但重点还是回顾一下这种题型。
#include <bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
const int maxn=1e5+7;
int n,m,T;
ll dp[30][30][2],sum,cnt;
bool f[30];
ll dfs(int pos,int pre,bool t){
if(pos==n) return 1;
if(dp[pos][pre][t]!=-1){
cnt++; //看节省了多少次遍历
return dp[pos][pre][t];
}
ll ans=0;
for(int i=1;i<=n;i++){
if(f[i]) continue;
if(t&&pre>i){
f[i]=1;
ans+=dfs(pos+1,i,0);
f[i]=0;
}
else if(!t&&pre<i){
f[i]=1;
ans+=dfs(pos+1,i,1);
f[i]=0;
}
}
return dp[pos][pre][t]=ans;
}
int main(){
cin>>T;
while(T--){
cin>>m>>n; sum=cnt=0;
memset(dp,-1,sizeof(dp)); memset(f,0,sizeof(f));
if(n==1){
printf("%d 1\n",m);
continue;
}
sum=(ll)dfs(0,0,0)*2;
printf("%d %lld\n",m,sum);
// cout<<cnt<<endl<<endl;
}
}
/*
4
1 1
2 3
3 4
4 20
1 1
2 4
3 10
4 740742376475050
*/
知识点:单调栈
题目大意:
给定一个数组,每次查询区间[l, r],
输出A[l] % A[l+1] % ... % A[r]
单调栈在这里的应用:查找区间任一个数字右边第一个比它小的数字
分析:
一开始数字为a[l],然后依次对a[l+1]到a[r]取模,即连续取模。
一个个暴力绝对T,但可以发现当前数字只会后面出现比它小的时才会改变,所以我们可以跳着取模。
线段树找右边第一小比较繁琐,但可以用单调栈。
复杂度:
预处理O(n),m次询问,理论上O(n+m),实际最坏情况下可以达到O(m*n*n),还好这题没卡数据
#include <bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
const int maxn=1e5+7;
int n,T,m,a[maxn],f[maxn],x,y,sum;
int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
return x*f;
}
int main(){
T=read();
while(T--){
n=read();
for(int i=1;i<=n;i++) a[i]=read();
stack<int>s;
for(int i=n;i>0;i--){
while(!s.empty()&&a[s.top()]>a[i]) s.pop();
if(s.empty()) f[i]=-1;
else f[i]=s.top();
s.push(i);
}
m=read();
while(m--){
x=read(); y=read();
if(x==y){
printf("%d\n",a[x]);
continue;
}
sum=a[x];
while(1){
int id=f[x];
if(id==-1||id>y) break;
sum%=a[id];
x=id;
}
printf("%d\n",sum);
}
}
}
/*
1
3
2 3 3
1
1 3
2
*/