首页 > 其他分享 >Educational Codeforces Round 142 (Rated for Div. 2)(C,D)

Educational Codeforces Round 142 (Rated for Div. 2)(C,D)

时间:2023-02-04 19:23:04浏览次数:59  
标签:Educational Rated 142 int rev include maxn 操作 排序

Educational Codeforces Round 142 (Rated for Div. 2)(C,D)

C

C

这道题的大意是题目大意是给你一个任意的排序,我们要把这个排序通过任意个操作变成一个有序的排序

操作是,选择任意两个数,大的那一个放在后面,小的那一个放在后面,问最少多少个操作才可以把这个排序变成有序的

在vp的过程中,感觉快知道答案了,但还是差一点,很迷糊,一团乱麻

先理一理

对于这些数,我感性的认为(对于此时n=5)

如果要选择两个数,1和5,在一起,2和4在一起进行操作

我们可以判断我们可以设一个l,一个r,l和r是从1到l-1的是符合顺序的,r-1到n是符合顺序的

什么是符合顺序的,我们在遍历的过程中,还有一个i,l要符合顺序就要让al和i是一样的,ar和n-i+1

如果不符合顺序,那么一定会需要i次操作

因为如果i和n-i+1这一对需要进行操作i个操作,因为如果进行了这一个操作,把i变到第一个了,我们要把1变到第一个位置,那么就还需要i-1个操作,总共i个操作

#include <iostream>
#include <vector>
using namespace std;
const int maxn=2e5+10;
#define int long long 
int t,n,a[maxn],pos[maxn];
bool vis[maxn];
void solve()
{
    cin>>n;
    for (int i=1;i<=n;i++)
    {
        cin>>a[i];
        vis[i]=false;
    }
    int ans=0;
    int l=1,r=n;
    for (int i=1;l<r&&i<=n;i++)
    {
        while (vis[a[l]])
        {
            l++;
        }
        while (vis[a[r]])
        {
            r--;
        }
        if (l>=r) break;
        if (a[l]!=i||a[r]!=n-i+1)//l,或者r至少有一个不满足,就需要操作了
        {
            ans=i;
        }
        vis[i]=vis[n-i+1]=true;//不管操作没操作,到这儿都一定是让i和n-i+1满足条件了
    }
    cout<<ans<<'\n';
    return ;
}
signed main ()
{
    cin>>t;
    while (t--)
    {
        solve();
    }
    system ("pause");
    return 0;
}

D

D

这个题的\(r_{i}=q_{p_{j}}\)看半天没看懂

先讲一下题目大意吧

这个是有n个长度为m的排序

对于ai(排序)和aj(排序)的乘积可以得到一个新的排序

新的排序就是

\(r_{i}=q_{p_{j}}\)

每种排序的值为从1到m的过程中,1到x是连续的1 2 3 。。。 x这种下标的数值一样的长度

问对于每一个排序,可以和某一个排序的值最大是多少

后来看了一些题解

要想\(r_{i}=q_{p_{i}}=i\),

我们可以看成\(q_{x}=i\),\(p_{i}=x\)

那么我们可以理解为

\(q\) 值为\(i\)的下标x

\(p\) 下标为\(i\)的值x

可以看出两个排序的乘积值越大,可以看成是,一个是原来的排序,一个将下标和值变一下,其中最大值为这两个排序的最长公共前缀和

求最长公共前缀和可以用到字典树

字典树一定要开大一点,我这道题数据是\(4e5\),我开了\(1e5\)都不够,至少要开到\(1e6\)那儿去

具体操作看代码

#include <iostream>
#include <vector>
using namespace std;
const int maxn=1000007;
#define int long long 
int n,m;
int tr[maxn][11];
int tot;
int t;
void insert(vector<int> s)
{
    int rt=0;
    for (int j=0;j<m;j++)
    {
        if (!tr[rt][s[j]])
        {
            tr[rt][s[j]]=++tot;
        }
        rt=tr[rt][s[j]];
    }
    return ;
}
int search(vector<int> s)
{
    int rt=0;
    for (int j=0;j<m;j++)
    {
        if (!tr[rt][s[j]]) return j;//如果这一个数没有找到,直接输出这一个的位置,因为下标是0到m-1的
        rt=tr[rt][s[j]];
    }
    return m;
}
vector<int>a[maxn],rev;
void solve()
{
    cin>>n>>m;
    rev=vector<int>(m);
    for (int i=0;i<n;i++)
    {
        a[i].clear();
        for (int j=0;j<m;j++)
        {
            int x;
            cin>>x;
            x--;//下标是从0到m-1
            a[i].push_back(x);
            rev[x]=j;
        }
        insert(rev);//rev为翻转
    }
    for (int i=0;i<n;i++)
    {
        cout<<search(a[i])<<' ';
    }
    cout<<'\n';
    for (int i=0;i<=tot;i++)//注意下一次可能会用到,要清除字典树
    {
        for (int j=0;j<10;j++)
        {
            tr[i][j]=0;
        }
    }
    tot=0;
    return ;
}
signed main ()
{
    cin>>t;
    while (t--)
    {
        solve();
    }
    system ("pause");
    return 0;
}

标签:Educational,Rated,142,int,rev,include,maxn,操作,排序
From: https://www.cnblogs.com/righting/p/17092186.html

相关文章