Educational Codeforces Round 142 (Rated for Div. 2)(C,D)
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
这个题的\(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