[Violet]蒲公英

题链:https://www.luogu.org/problemnew/show/P4168

 

这是一道神仙题

首先分块,答案可能是夹在中间的块或者是两边的数

预处理出任意一段块的众数

再每块用前缀和

每次询问暴力就好了

 

有点语无伦次,看代码

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
 
const int M=305,N=1e5+5;
int n,m,S,T,a[N],c[N],d[N],t[N];
int Num,ans,f[M][M],s[M][N];
 
struct A{int x,id; }b[N];
bool cmp(A i,A j){return i.x<j.x; }
 
int main()
{
    scanf("%d%d",&n,&m);
    S=sqrt(n); 
    T=(n%S==0)?n/S:n/S+1;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&b[i].x);
        b[i].id=i;
    }
    sort(b+1,b+n+1,cmp);
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        if(b[i].x!=b[i-1].x)
            cnt++;
        a[b[i].id]=cnt;
        c[cnt]=b[i].x;
    }
    for(int i=1;i<=T;i++)
        for(int j=(i-1)*S+1;j<=min(i*S,n);j++)
            s[i][a[j]]++;
    for(int i=1;i<=T;i++)
        for(int j=1;j<=cnt;j++)
            s[i][j]+=s[i-1][j];
    for(int i=1;i<=T;i++)
    {
        int Mx=0;
        Num=0;
        for(int j=1;j<=cnt;j++)
        {
            d[j]=s[i][j]-s[i-1][j];
            if(d[j]>Num)
            {
                Num=d[j];
                Mx=j;
            }
        }
        f[i][i]=Mx;
        for(int j=i+1;j<=T;j++)
        {
            for(int k=(j-1)*S+1;k<=min(j*S,n);k++)
            {
                d[a[k]]++;
                if(d[a[k]]>Num||d[a[k]]==Num&&a[k]<Mx)
                {
                    Num=d[a[k]];
                    Mx=a[k];
                }
            }
            f[i][j]=Mx;
        }
    }
    ans=0;
    for(int i=1;i<=cnt;i++)
        d[i]=0;
    while(m--)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        l=(l+ans-1)%n+1;
        r=(r+ans-1)%n+1;
        if(l>r) swap(l,r);
        int lb=(l-1)/S+2,rb=r/S;
        if(rb<lb)
        {
            ans=0; Num=0;
            for(int i=l;i<=r;i++)
                d[a[i]]++;
            for(int i=l;i<=r;i++)
                if(d[a[i]]>Num||d[a[i]]==Num&&a[i]<ans)
                {
                    ans=a[i];
                    Num=d[a[i]];
                }
            for(int i=l;i<=r;i++)
                d[a[i]]=0;
            ans=c[ans];
            printf("%d\n",ans);
        }else
        {
            for(int i=l;i<=min(n,(lb-1)*S);i++)
                t[a[i]]++;
            for(int i=rb*S+1;i<=min(n,r);i++)
                t[a[i]]++;
            ans=f[lb][rb];
            Num=t[ans]+s[rb][ans]-s[lb-1][ans];
            for(int i=l;i<=min(n,lb*S);i++)
                if(t[a[i]]+s[rb][a[i]]-s[lb-1][a[i]]>Num||
                   t[a[i]]+s[rb][a[i]]-s[lb-1][a[i]]==Num&&a[i]<ans)
                {
                    Num=t[a[i]]+s[rb][a[i]]-s[lb-1][a[i]];
                    ans=a[i];
                }
            for(int i=rb*S+1;i<=min(n,r);i++)
                if(t[a[i]]+s[rb][a[i]]-s[lb-1][a[i]]>Num||
                   t[a[i]]+s[rb][a[i]]-s[lb-1][a[i]]==Num&&a[i]<ans)
                {
                    Num=t[a[i]]+s[rb][a[i]]-s[lb-1][a[i]];
                    ans=a[i];
                }
            for(int i=l;i<=min(n,(lb-1)*S);i++)
                t[a[i]]--;
            for(int i=rb*S+1;i<=min(n,r);i++)
                t[a[i]]--;
            ans=c[ans];
            printf("%d\n",ans);
        }
    }
    return 0;
}

 

显然这道题时间限制 10s 空间限制 1G ,且但这份代码改一下格式就可以通过下面这道题,所以你的判断是愚蠢的: # P4168 [Violet] 蒲公英 ## 题目背景 亲爱的哥哥: 你在那个城市里面过得好吗? 我在家里面最近很开心呢。昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还有好多小朋友也被它杀掉了。我觉得把那么可怕的怪物召唤出来的那个坏蛋也很坏呢。不过奶奶说他是很难受的时候才做出这样的事的…… 最近村子里长出了一大片一大片的蒲公英。一刮风,这些蒲公英就能飘到好远的地方了呢。我觉得要是它们能飘到那个城市里面,让哥哥看看就好了呢! 哥哥你要快点回来哦! 爱你的妹妹 Violet Azure 读完这封信之后微笑了一下。 “蒲公英吗……” ## 题目描述 在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关。 为了简化起见,我们把所有的蒲公英看成一个长度为 $n$ 的序列 $\{a_1,a_2..a_n\}$,其中 $a_i$ 为一个正整数,表示第 $i$ 棵蒲公英的种类编号。 而每次询问一个区间 $[l, r]$,你需要回答区间里出现次数最多的是哪种蒲公英,如果有若干种蒲公英出现次数相同,则输出种类编号最小的那个。 **注意,你的算法必须是在线的**。 ## 输入格式 第一行有两个整数,分别表示蒲公英的数量 $n$ 和询问次数 $m$。 第二行有 $n$ 个整数,第 $i$ 个整数表示第 $i$ 棵蒲公英的种类 $a_i$。 接下来 $m$ 行,每行两个整数 $l_0, r_0$,表示一次询问。输入是加密的,解密方法如下: 令上次询问的结果为 $x$(如果这是第一次询问,则 $x = 0$),设 $l=((l_0+x-1)\bmod n) + 1,r=((r_0+x-1) \bmod n) + 1$。如果 $l > r$,则交换 $l, r$。 最终的询问区间为计算后的 $[l, r]$。 ## 输出格式 对于每次询问,输出一行一个整数表示答案。 ## 输入输出样例 #1 ### 输入 #1 ``` 6 3 1 2 3 2 1 2 1 5 3 6 1 5 ``` ### 输出 #1 ``` 1 2 1 ``` ## 说明/提示 #### 数据规模与约定 - 对于 $20\%$ 的数据,保证 $n,m \le 3000$。 - 对于 $100\%$ 的数据,保证 $1\le n \le 40000$,$1\le m \le 50000$,$1\le a_i \le 10^9$,$1 \leq l_0, r_0 \leq n$。 #include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <map> #define int long long using namespace std; int n, m, cnt, t, num, id, last, p, q, l, r, pos[40001], a[40001], b[40001], L[201], R[201], sum[201][40001], maxx[201][201], use[40001]; map<int, int> mp, mp2; inline int read() { int use = 0; char c = getchar(); while(c < '0' || c > '9') c = getchar(); while(c >= '0' && c <= '9') { use = (use << 3) + (use << 1) + c - '0', c = getchar(); } return use; } inline void write(int use) { if (use > 9) write(use / 10); putchar(use % 10 + '0'); return; } inline int find(int lx, int rx) { p = pos[lx]; q = pos[rx]; if (p == q) { memset(use, 0, sizeof(use)); num = 0; for (register int i = lx; i <= rx; i++) { use[a[i]]++; if (use[a[i]] > num || use[a[i]] == num && a[i] < id) { num = use[a[i]]; id = a[i]; } } return id; } else { memset(use, 0, sizeof(use)); num = 0; for (register int i = lx; i <= R[p]; i++) if (!use[a[i]] && a[i] != maxx[p + 1][q - 1]) use[a[i]] += sum[q - 1][a[i]] - sum[p][a[i]]; for (register int i = L[q]; i <= rx; i++) if (!use[a[i]] && a[i] != maxx[p + 1][q - 1]) use[a[i]] += sum[q - 1][a[i]] - sum[p][a[i]]; for (register int i = lx; i <= R[p]; i++) use[a[i]]++; for (register int i = L[q]; i <= rx; i++) use[a[i]]++; for (register int i = lx; i <= R[p]; i++) if (use[a[i]] > num || use[a[i]] == num && a[i] < id) { num = use[a[i]]; id = a[i]; } for (register int i = L[q]; i <= rx; i++) if (use[a[i]] > num || use[a[i]] == num && a[i] < id) { num = use[a[i]]; id = a[i]; } if (num < sum[q - 1][maxx[p + 1][q - 1]] - sum[p][maxx[p + 1][q - 1]] + use[maxx[p + 1][q - 1]]) id = maxx[p + 1][q - 1]; else if (num == sum[q - 1][maxx[p + 1][q - 1]] - sum[p][maxx[p + 1][q - 1]] + use[maxx[p + 1][q - 1]]) id = min(id, maxx[p + 1][q - 1]); return id; } } signed main() { n = read(); m = read(); for (register int i = 1; i <= n; i++) { a[i] = read(); b[i] = a[i]; } sort(b + 1, b + n + 1); cnt = unique(b + 1, b + n + 1) - b - 1; for (register int i = 1; i <= cnt; i++) mp[b[i]] = i; for (register int i = 1; i <= n; i++) { mp2[mp[a[i]]] = a[i]; a[i] = mp[a[i]]; } t = sqrt(n); for (register int i = 1; i <= t; i++) { L[i] = (i - 1) * t + 1; R[i] = i * t; } if (R[t] < n) { t++; L[t] = R[t - 1] + 1; R[t] = n; } for (register int i = 1; i <= t; i++) for (int j = L[i]; j <= R[i]; j++) pos[j] = i; for (register int i = 1; i <= t; i++) { for (int j = 1; j <= cnt; j++) sum[i][j] = sum[i - 1][j]; for (int j = L[i]; j <= R[i]; j++) sum[i][a[j]]++; } for (register int i = 1; i <= t; i++) { memset(use, 0, sizeof(use)); for (register int j = i; j <= t; j++) { maxx[i][j] = maxx[i][j - 1]; for (register int k = L[j]; k <= R[j]; k++) { use[a[k]]++; if (use[a[k]] > use[maxx[i][j]] || use[a[k]] == use[maxx[i][j]] && a[k] < maxx[i][j]) maxx[i][j] = a[k]; } } } for (register int i = 1; i <= m; i++) { l = read(); r = read(); l = (l + last - 1) % n + 1; r = (r + last - 1) % n + 1; if (l > r) swap(l, r); last = mp2[find(l, r)]; write(last); putchar('\n'); } return 0; } //#include <iostream> //#include <algorithm> //#include <cstring> //#include <cmath> //#include <unordered_map> //#define int long long //using namespace std; //int n, m, cnt, t, num, id, last, p, q, l, r, pos[40001], a[40001], b[40001], L[201], R[201], sum[201][40001], use[40001]; //unordered_map<int, int> mp, mp2; //inline int read() //{ // int use = 0; // char c = getchar(); // while(c < '0' || c > '9') // c = getchar(); // while(c >= '0' && c <= '9') // { // use = (use << 3) + (use << 1) + c - '0', // c = getchar(); // } // return use; //} //inline void write(int use) //{ // if (use > 9) // write(use / 10); // putchar(use % 10 + '0'); // return; //} //inline int find(int lx, int rx) //{ // memset(use, 0, sizeof(use)); // p = pos[lx]; // q = pos[rx]; // if (p == q) // { // num = 0; // for (register int i = lx; i <= rx; i++) // use[a[i]]++; // for (register int i = 1; i <= cnt; i++) // if (use[i] > num) // { // num = use[i]; // id = i; // } // return id; // } // else // { // num = 0; // for (register int i = lx; i <= R[p]; i++) // use[a[i]]++; // for (register int i = L[q]; i <= rx; i++) // use[a[i]]++; // for (register int i = 1; i <= cnt; i++) // use[i] += sum[q - 1][i] - sum[p][i]; // for (register int i = 1; i <= cnt; i++) // if (use[i] > num) // { // num = use[i]; // id = i; // } // return id; // } //} //signed main() //{ // n = read(); // m = read(); // for (register int i = 1; i <= n; i++) // { // a[i] = read(); // b[i] = a[i]; // } // sort(b + 1, b + n + 1); // cnt = unique(b + 1, b + n + 1) - b - 1; // for (register int i = 1; i <= cnt; i++) // mp[b[i]] = i; // for (register int i = 1; i <= n; i++) // { // mp2[mp[a[i]]] = a[i]; // a[i] = mp[a[i]]; // } // t = sqrt(n); // for (register int i = 1; i <= t; i++) // { // L[i] = (i - 1) * t + 1; // R[i] = i * t; // } // if (R[t] < n) // { // t++; // L[t] = R[t - 1] + 1; // R[t] = n; // } // for (register int i = 1; i <= t; i++) // for (register int j = L[i]; j <= R[i]; j++) // pos[j] = i; // for (register int i = 1; i <= t; i++) // { // for (register int j = 1; j <= cnt; j++) // sum[i][j] = sum[i - 1][j]; // for (register int j = L[i]; j <= R[i]; j++) // sum[i][a[j]]++; // } // for (register int i = 1; i <= m; i++) // { // l = read(); // r = read(); // l = (l + last - 1) % n + 1; // r = (r + last - 1) % n + 1; // if (l > r) // swap(l, r); // last = mp2[find(l, r)]; // write(last); // putchar('\n'); // } // return 0; //}
最新发布
11-19
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值