Codeforces Round #686 (Div. 3)(A->D)(模拟,vector,数学)

A:https://codeforces.com/contest/1454/problem/A

题意:

输出1~n的一个排列,满足每个i!=pi

解析:

偶数直接倒叙

奇数不能倒叙,因为中间点不符合。所以随便调下位置即可。比如先输出n,然后正序输出1~n-1

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int main()
{    
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        if(n%2)
        {
            cout<<n<<" ";
            for(int i=1;i<=n-1;i++)
                cout<<i<<" ";
        }
        else
        {
            for(int i=n;i>=1;i--)
                cout<<i<<" ";
        }
        cout<<endl;
    }
}

B:https://codeforces.com/contest/1454/problem/B

题意:

给出n个数,是否某个数只出现了一次,而且在所有出现一次的数中最小。

解析:

俩memset hack掉了。

其实计坐标的那个数组压根不需要重置。每次都被覆盖了。。。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
int a[maxn];
int v1[maxn],v2[maxn];
int main()
{    
    int t;
    cin>>t;
    while(t--)
    {
        memset(v1,0,sizeof(v1));
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            int x;
            cin>>x;
            v1[x]++;
            v2[x]=i;
        }
        int ok=0,idx;
        for(int i=1;i<=n;i++)
        {
            if(v1[i]==1)
            {
                ok=1;
                idx=v2[i];
                break;
            }
        }
        if(ok)
            cout<<idx<<endl;
        else
            cout<<"-1"<<endl;
    }
}

C:https://codeforces.com/contest/1454/problem/C

题意:

给出n个数

只能选择一个数字x,然后每次都要消一个[L,R],[L,R]中不能包含x

使得数列全相等的最少操作数

解析:

开始以为是贪心,但是光看样例就给否定了。原来是个模拟。

那么就考虑,对每个数字的出现位置进行记录,每次算一下如果选它需要的操作数,取个最小值就行了。

但是细节是颇多的。其实对比别人的话,我是写的有点太丑了。。。。。vector写的比较简单,看来还是太菜了。。。

具体注释看代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
const int inf=99999999;
int a[maxn];
int v1[maxn],v2[maxn];
int main()
{    
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
            v1[i]=0;
        memset(v2,0,sizeof(v2));//记录每个数的操作数
        map<int,int>mp;//记录出现次数
        int minn=inf;int maxx=0;
        int sum=0;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            int cnt=0;
            mp[a[i]]++;
            if(v1[a[i]]==0)//之前没出现过
            {
                if(i==1)//目前处于开头,那么不需要操作
                    cnt=0;
                else
                    cnt=1;
            }
            else
            {
                if(v1[a[i]]+1==i)//如果出现过,而且和上次出现位置相邻,不需操作
                    cnt=0;
                else
                    cnt=1;
            }
            v1[a[i]]=i;
            v2[a[i]]+=cnt;            
        }
        for(int i=1;i<=n;i++)//对最后出现不在末尾的,操作+1
        {
            if(v1[i]<n&&mp[i]>0)
            {
                
                v2[i]++;
            }
        }
//        for(int i=1;i<=n;i++)
//            cout<<v2[i]<<" ";
//            cout<<"--"<<endl;
        int ok=0;
        for(int i=1;i<n;i++)
        {
            if(a[i]!=a[i+1])
            {
                ok=1;
                break;
            }
        }
        if(ok==0)  //全相等
            cout<<"0"<<endl;
        else
        {for(int i=1;i<=n;i++)
            {
                if(v2[i]!=0)
                minn=min(minn,v2[i]);
            }
            cout<<minn<<endl;
        }
    }
}

来个vector版的吧,vector<vector<int>>v(n+10);

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<stack>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
const int inf=99999999;
int a[maxn];
int v1[maxn],v2[maxn];
int main()
{    
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        int x;
        vector<vector<int>>v(n+10);
        for(int i=1;i<=n;i++)
        {
            cin>>x;
            v[x].push_back(i);
        }
        int minn=inf;
        for(int i=1;i<=n;i++)
        {
            if(v[i].empty())
                continue;
            int md=2;//默认i的个出现位置,都处于2~n-1之间,所以默认操作2次
            for(int j = 1 ; j < v[i].size();j++)//算的是所有数之间,不包括两边
            {
                if(v[i][j]>v[i][j-1]+1)//不相邻
                    md++;
            }
            if(v[i][0]==1)//初始处于第一个位置,md--
                md--;
            if(v[i][v[i].size()-1]==n)//同理
                md--;
            minn=min(minn,md);
        }
        cout<<minn<<endl;
    }
    return 0;
}

D:https://codeforces.com/contest/1454/problem/D

题意:

给出n

输出最长的一组数,它们的乘积能被n整除。而且ai能够整除ai-1

解析:

根据唯一分解定理:

找出出现次数最多的质因子,设出现次数x

那么先输出前x-1个,然后剩下那个乘到其他因数上变成一体就好了。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
int a[maxn];
int v1[maxn],v2[maxn];
int main()
{    
    int t;
    cin>>t;
    while(t--)
    {
        ll n,nn;
        cin>>n;
        nn=n;
        int sum=0;
        map<ll,int>m;
        for(int i=2;i<=n/i;i++)
        {
            while(n%i==0)
            {
                n=n/i;
                m[i]++;
                sum++;
            }
        }
        if(n>1)
        {
            m[n]++;
            sum++;
        }
        ll maxx=0;
        ll md;
        for(int i=2;i<=nn/i;i++)
        {
            if(nn%i==0)
            {
                if(maxx<m[i])
                {
                    maxx=m[i];
                    md=i;
                }
            }
        }
        if(maxx==0)
            maxx=1;
        cout<<maxx<<endl;
        ll all=1;
        for(int i=1;i<=maxx-1;i++)
        {
            cout<<md<<" ";
            all*=md;
            m[md]--;
        }
        cout<<nn/all<<endl;    
    }
    return 0;
}
原文地址:https://www.cnblogs.com/liyexin/p/14038484.html