NYG的动态数点

来源:互联网 发布:股票评测软件 编辑:程序博客网 时间:2024/05/16 15:47

9.19
思路:
std的题解:
算法一
直接上暴力模拟,枚举每一个区间,时间复杂度O(n3)。
期望得分30分。
算法二
枚举一个左端点,然后开一个桶,再往右扫过去。
每一次加入一个数更新一下当前的gcd,然后看区间中是否存在这个数。
时间复杂度O(n2 log(n))
期望得分60分。
算法三
开始用ST表预处理一下区间gcd,以及区间最小值。
二分区间长度,然后每一次check扫过去,看是否有区间最小值和gcd相等。
时间复杂度O(n log2(n))
如果你写得丑,或者没有开long long,期望得分80分。
如果你颜值高,然后又聪明机智(就像NYG一样),期望得分100分。

然而std并没有提到我这种歪门邪道。。。
考虑找到任意一个数作为k,然后向两边扩张。如果被包含进区间了,就说明ak|ai,所以由ai作为k的扩展区间一定被ak的区间真包含,(自己YY一下就知道了)。所以ai就不用枚举啦!这样一来每个数最多会被统计1次,所以就是O(n)的啦:-)

#include <iostream>#include <algorithm>#include <cstdio>using namespace std;const int N = 500010;int n, idc=0, cnt=0, maxn=0;int vis[N], ans[N];struct AA{    int val, pos, flag;}a[N], b[N];bool cmp(AA aa, AA bb){    return aa.val < bb.val;}bool cmp1(int aa, int bb){    return aa < bb;}int main(){    freopen ("point.in", "r", stdin);    freopen ("point.out", "w", stdout);    scanf("%d", &n);    for(register int i=1; i<=n; i++){        scanf("%d", &a[i].val);        a[i].pos = i;        b[i].val = a[i].val;        b[i].pos = a[i].pos;    }    sort(b+1, b+1+n, cmp);    while (true){        while (a[b[++idc].pos].flag == 1);        if(idc == n+1) break;        int p = b[idc].pos;        int cc = p; a[p].flag = 1;        while(a[--cc].val % a[p].val == 0 && cc >= 1) {            a[cc].flag = 1;        }        ans[++cnt] = cc + 1;        cc = p;        while(a[++cc].val % a[p].val == 0 && cc <= n) {            a[cc].flag = 1;        }        int L = cc - 1 - ans[cnt];        if(L > maxn){            maxn = L; ans[1] = ans[cnt]; cnt = 1;        }        if(L < maxn) cnt--;    }    printf("%d %d\n", cnt, maxn);    sort(ans+1, ans+1+cnt, cmp1);    for(register int i=1; i<=cnt; i++){        printf("%d ", ans[i]);    }    return 0;}
原创粉丝点击