选择客栈
原题
这道题,一开始是想着用递推的,然后后来想着想着想复杂了,就开始用st表了。
st表的话
#include<bits/stdc++.h>
using namespace std;
int color[200010];
int w[200010];
int n,k,p;
vector<int> v;
int st[200010][22];
int a[200010];
int ans=0;
int ask(int x,int y){
int l=log(y-x+1)/log(2);
return min(st[x][l],st[y-(1<<l)+1][l]);
}
void prev(){
for(int i=1;i<=n;i++){
st[i][0]=a[i];
}
for(int j=1;j<=p;j++){
for(int i=1;i<=n;i++){
st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
}
}
int main(){
cin>>n>>k>>p;
int p=log(n)/log(2)+1;
for(int i=1;i<=n;i++){
cin>>color[i]>>a[i];
}
prev();
for(int c=0;c<k;c++){
bool first=true;
int tot=0;
int ddd=0;
v.clear();
for(int i=1;i<=n;i++){
if(color[i]==c&&first){
v.push_back(i);
tot++;
first=false;
}
else if(color[i]==c){
for(int j=0;j<tot;j++){
if(ask(v[j],i)<=p){
ddd++;
}
}
v.push_back(i);
tot++;
}
}
ans+=ddd;
}
cout<<ans;
}
这样莫名其妙RE?不知道为什么,而且感觉这个代码太过复杂。
由于实在不会递推了?
我只能想到,从1到n这些点一个个扫过去,如果这个客栈的颜色和
就上面这行图片,我想的是如果1和2和合法的,那么必然1和3是合法的,但是2和3是不是合法的就不知道了,还要看他们中间的。
这时候我就开始迷茫,不知道怎么处理
后来看了题解。
其实就是从前往后扫描
now表示的离当前最近的合法的点的位置(不要求颜色相同)
cnt表示走到当前的时候,i颜色的有多少个
sum就是走到当前位置的时候,前面合法的i颜色的个数
结合代码
#include<bits/stdc++.h>
using namespace std;
int last[10010],sum[10010];
int cnt[100010];
int main(){
int ans=0;
int n,k,p;
int now;
cin>>n>>k>>p;
for(int i=1;i<=n;i++){
int price;
int color;
cin>>color>>price;
if(price<=p){//如果他是合法的
now=i;
}
if(now>=last[color]){
sum[color]=cnt[color];
}
last[color]=i;
ans+=sum[color];
cnt[color]++;
}//从1到n开推
cout<<ans;
}
就是说,我们一个个扫描过去,如果发现有price<=p的
也就是要更新now;
now的作用是最重要的
如果now>=last[color],如果合法的数字比上一次出现这个要早
也就是这个合法的东西夹在我们当前数字和上一次数字之间
同时那么当前这个位置必然可以和前面的所有和他一个颜色的客栈组成搭配
就是说sum[i]=cnt[color]
但是,不管这个合法不合法,他总是可以和上一次的相加
因为正如上面图片所说的,1和2合法,1和3必然合法
其实我认为这里有一点贪心,就是now,只要now是合法的(也就是now的pirce是小于等于p的),我们就可以他这次出现的给统计了,为了使得now经尽量能够在后面,这样才能使得尽量满足可能的now>=last[color],所有情况才会被考虑到
所以答案就加上已经合法的东西;
这时间复杂度真低……
还是挺不容易想的……