CF352B 题解

题意

这道题题目看上去花里胡哨,其实就是道水题。

题目大意就是说将每个相同数出现的下标(从 $1$ 开始)统计一下,如果这些下标所构成的数列是等差数列那就输出这个重复出现的数以及等差数列的公差。

是不是没懂?

举个例子,如样例二:

8
1 2 1 3 1 2 1 5

$1$ 出现了三次,分别在下标 $1,3,5,7$ 的位置上,而 $1,3,5,7$ 是一个等差数列,公差为 $2$,因此应该输出 $1$ $2$,其中 $1$ 是这个数, $2$ 是等差数列的公差。

然后是 $2$,它出现了两次,分别在下标 $2,6$ 的位置上,$2,6$ 也是一个等差数列,公差为 $4$,因此输出 $2,4$。

再看 $3$ 和 $5$,这两个数只出现了一次,所以直接输出 $3,0$ 和 $5,0$。

思路

本题由于要考虑重复出现的数字,所以大部分大佬直接开始用桶做,但是不要忘了我们学的可是一个面向对象的语言,可以使用 STL 来做啊。

首先是数字下标的存储方面,由于只需要考虑下标,没必要记录每一个数字,所以不需要再额外开数组,存储方式有点像邻接表的存储。

int n;
cin>>n;
for(int i=1;i<=n;i++){//下标从1开始!!! 
    int x;
    cin>>x;
    v[x].push_back(i);//记录数值的下标 
}

然后就是对于等差数列的判断了。

我们可以先计算第一个数和第二个数之间的差,记作 $d$,然后扫描数组,如果相邻的两个数之间的差都等于 $d$ 的话那就说明是一个等差数组。

for(int i=0;i<N;i++){
    if(v[i].empty()) continue;
    if(v[i].size()==1){//特判只出现一次的情况 
        //记录答案 
        continue;
    }
    //下面可能有点绕,可以把v[i]看成一个整体来阅读 
    int d=v[i][1]-v[i][0];
    bool flag=false;
    for(int j=1;j<v[i].size()-1;j++){
        if(v[i][j+1]-v[i][j]!=d){//不符合情况 
            flag=true;
            break;
        }
    }
    if(flag==false){
        //记录答案 
    }
}

就差最后一步了,那就是记录答案了。

我们可以发现,答案包括两个部分,数值与公差,既然是两个部分捆绑在一起,很容易想到结构体数组,但是不要忘了我们学的可是一个面向对象的语言,可以使用 STL 来做啊。

可以考虑开一个结构体类型的队列来进行存储,由于队列是一种先进先出的容器,因此我们无需再次考虑数据有序的问题。

for(int i=0;i<N;i++){
    if(v[i].empty()) continue;
    if(v[i].size()==1){//特判只出现一次的情况 
        ans.push({i,0});//直接入队 
        continue;
    }
    //下面可能有点绕,可以把v[i]看成一个整体来阅读 
    int d=v[i][1]-v[i][0];
    bool flag=false;
    for(int j=1;j<v[i].size()-1;j++){
        if(v[i][j+1]-v[i][j]!=d){//不符合情况 
            flag=true;
            break;
        }
    }
    if(flag==false){
        ans.push({i,d});//如果满足情况,直接入队 
    }
}

最后我们会发现,答案的个数不就是队列的长度吗,所以我们可以直接输出队列长度和队中元素。

cout<<ans.size()<<endl;
while(!ans.empty()){
    cout<<ans.front().val<<" "<<ans.front().d<<endl;//val为数值,d是公差 
    ans.pop();
}

完整代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
struct node{//结构体 
    int val,d;//val为数值,d是公差 
}; 
vector<int> v[N];
queue<node> ans; 
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){//下标从1开始!!! 
        int x;
        cin>>x;
        v[x].push_back(i);//记录数值的下标 
    }
    for(int i=0;i<N;i++){
        if(v[i].empty()) continue;
        if(v[i].size()==1){//特判只出现一次的情况 
            ans.push({i,0});//直接入队 
            continue;
        }
        //下面可能有点绕,可以把v[i]看成一个整体来阅读 
        int d=v[i][1]-v[i][0];
        bool flag=false;
        for(int j=1;j<v[i].size()-1;j++){
            if(v[i][j+1]-v[i][j]!=d){//不符合情况 
                flag=true;
                break;
            }
        }
        if(flag==false){
            ans.push({i,d});//如果满足情况,直接入队 
        }
    }
    cout<<ans.size()<<endl;
    while(!ans.empty()){
        cout<<ans.front().val<<" "<<ans.front().d<<endl;
        ans.pop();
    }
    return 0;
}
posted @ 2023-11-19 08:56  very_easy  阅读(36)  评论(0)    收藏  举报  来源