7.26

7.26

题目:https://blog.csdn.net/weixin_30952103/article/details/101591104

礼物

概率dp

通讯

有向图tarjan

奇袭

由于题水。。。\(O(N^2)\)算法也可过,话说考试那天我就想了个\(O(N^5)\)...

O(N^2)算法:

由于军队的横纵坐标各不相同,所以原问题可以转换为序列问题:给定一个1−n的排列,求这个序列中有多少个子序列满足子序列中的数字恰好是连续的一串数。很容易可以知道,子区间[l,r]符合要求,就会有max[l,r]−min[l,r]=r−l

用st表为何max[] 和min[]

然后查一段里 mx ( i , j ) - mi ( i , j ) == j - i

然后小优化——如果上述判断不成立,j=mx ( i , j ) - mi ( i , j ) + i

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N=5e4+5;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return f*x;
}

int n;
int mi[N][20],mx[N][20],lg[N];
void init() {
    memset(mi,0x3f,sizeof mi);
    memset(mx,0,sizeof mx);
}
inline int query_mi(int i,int j) {
    int k=lg[j-i+1];
    return min(mi[i][k],mi[j-(1<<k)+1][k]);
}
inline int query_mx(int i,int j) {
    int k=lg[j-i+1];
    return max(mx[i][k],mx[j-(1<<k)+1][k]);
}
int ans;
int main() {
    init();
    n=read();
    for(int i=1,x,y;i<=n;i++) {
        x=read();y=read();
        mi[i][0]=mx[i][0]=y;
    }
    for(int i=2;i<=n+1;i++)
        lg[i]=lg[i>>1]+1;
    for(int j=1;j<=18;j++)
        for(int i=1;i+(1<<j)-1<=n;i++) 
            mi[i][j]=min(mi[i][j-1],mi[i+(1<<(j-1))][j-1]),
            mx[i][j]=max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]);
    ans=n;
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;) {
            int cha=query_mx(i,j)-query_mi(i,j);
            if(cha==j-i) ans++,j++;
            else j=i+cha;
        }
    printf("%d\n",ans);
    return 0;
}

正解:分治

见链接https://www.cnblogs.com/Juve/p/11198809.html

posted @ 2020-08-25 15:03  ke_xin  阅读(30)  评论(0编辑  收藏  举报