A. Greatest Convex
x
!
+
(
x
−
1
)
!
=
1
∗
2
∗
.
.
.
∗
(
x
−
1
)
∗
(
x
+
1
)
x!+(x-1)!=1*2*...*(x-1)*(x+1)
x!+(x−1)!=1∗2∗...∗(x−1)∗(x+1)
然后
1
≤
x
<
k
1{\leq}x<k
1≤x<k,所以x=k-1就行了
#include <iostream>
#include <cstring>
#include <algorithm>
#define fir(i,a,b) for(int i=a;i<=b;i++)
typedef long long LL;
#define met(x,y) memset(x,y,sizeof x)
//#define read(x) scanf("%d",&x)
using namespace std;
typedef pair<int,int> PII;
int read()
{
char ch = getchar(); int x = 0, w = 1;
while (ch < '0' || ch>'9') { if (ch == '-')w = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + ch - '0';
ch = getchar(); }
return x*w;
}
int main()
{
//freopen("test.txt", "r", stdin);
int t=read();
while(t--)
{
int n=read();
cout<<n-1<<endl;
}
//freopen("CON", "r", stdin);
//system("pause");
return 0;
}
B. Quick Sort
一次操作可以将k个数有序,那么就可以计算排列有序的数量,即n在p数组的下标大于n-1在p数组的下标,n从2开始看能到几。
#include <iostream>
#include <cstring>
#include <algorithm>
#define fir(i,a,b) for(int i=a;i<=b;i++)
typedef long long LL;
#define met(x,y) memset(x,y,sizeof x)
//#define read(x) scanf("%d",&x)
using namespace std;
typedef pair<int,int> PII;
const int N = 1e5+10;
int a[N];
int read()
{
char ch = getchar(); int x = 0, w = 1;
while (ch < '0' || ch>'9') { if (ch == '-')w = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + ch - '0';
ch = getchar(); }
return x*w;
}
int main()
{
//freopen("test.txt", "r", stdin);
int t=read();
while(t--)
{
int n=read(),k=read();
for(int i=0;i<n;i++)a[i]=read();
int t=1;
for(int i=0;i<n;i++)if(a[i]==t)t++;
if(t>n)puts("0");
else cout<<(n-t)/k+1<<endl;
}
//freopen("CON", "r", stdin);
//system("pause");
return 0;
}
C. Elemental Decompress
设最终2个数组为
x
[
N
]
,
y
[
N
]
x[N],y[N]
x[N],y[N]
先用一个数组
c
n
t
[
N
]
cnt[N]
cnt[N]记下每个数出现的次数,如果有一个数的次数大于2就可以直接NO了
再用两个数组
l
[
N
]
,
r
[
N
]
l[N],r[N]
l[N],r[N]记下,每个数出现的位置,因为最多两次,所以用两个数组
再从1到n遍历一下
- 如果 i i i出现的次数为1, x [ l [ i ] ] = i , y [ l [ i ] = i x[l[i]]=i,y[l[i]=i x[l[i]]=i,y[l[i]=i
- 如果 i i i出现的次数为2,可以用一个 v e c t o r < i n t > c y vector<int>cy vector<int>cy记录i
- 如果 i i i出现的次数为0,可以用一个 v e c t o r < i n t > c x vector<int>cx vector<int>cx记录i
对cx和cy进行sort一下
如果
c
x
.
s
i
z
e
(
)
!
=
c
y
.
s
i
z
e
(
)
cx.size()!=cy.size()
cx.size()!=cy.size()或者
c
x
[
i
]
>
c
y
[
i
]
cx[i]>cy[i]
cx[i]>cy[i]就NO
再遍历一下cy让所有的
c
y
[
i
]
对应
c
x
[
i
]
cy[i]对应cx[i]
cy[i]对应cx[i]
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#define fir(i, a, b) for (int i = a; i <= b; i++)
typedef long long LL;
#define met(x, y) memset(x, 0, 4*(n+5))
//#define read(x) scanf("%d",&x)
using namespace std;
typedef pair<int, int> PII;
const int N = 2e5 + 10;
int a[N];
int x[N], y[N];
int cnt[N];
int l[N], r[N];
vector<int> cx, cy;
int read()
{
char ch = getchar();
int x = 0, w = 1;
while (ch < '0' || ch > '9')
{
if (ch == '-')
w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + ch - '0';
ch = getchar();
}
return x * w;
}
int main()
{
// freopen("test.txt", "r", stdin);
int t = read();
while (t--)
{
int n = read();
met(cnt, n);
met(l, n);
met(r, n);
cx.clear(), cy.clear();
bool fl = true;
for (int i = 1; i <= n; i++)
a[i] = read();
for (int i = 1; i <= n; i++)
{
cnt[a[i]]++;
if (l[a[i]] == 0)
l[a[i]] = i;
else
r[a[i]] = i;
if (cnt[a[i]] > 2)
fl = false;
}
if (!fl)
{
puts("NO");
continue;
}
for (int i = 1; i <= n; i++)
{
if (cnt[i] == 1)
x[l[i]] = i, y[l[i]] = i;
else if (cnt[i] == 0)
cx.push_back(i);
else
cy.push_back(i);
}
//cout<<cx.size();
if (cx.size() != cy.size())
fl = false;
if (!fl)
{
puts("NO");
continue;
}
for (int i = 0; i < cx.size(); i++)
if (cx[i] > cy[i])
fl = false;
if (!fl)
{
puts("NO");
continue;
}
for(int i=0;i<cy.size();i++)
{
x[l[cy[i]]]=cy[i],y[r[cy[i]]]=cy[i],y[l[cy[i]]]=cx[i],
x[r[cy[i]]]=cx[i];
}
puts("YES");
for(int i=1;i<=n;i++)cout<<x[i]<<" ";
puts("");
for(int i=1;i<=n;i++)cout<<y[i]<<" ";
puts("");
}
// freopen("CON", "r", stdin);
// system("pause");
return 0;
}
D. Lucky Permutation
这个当时一点思路都没有,主要是看这个
链接
我复制粘贴一下,代码自己写的
本题可能需要了解群论里的部分结论.
首先逆序对为1其实就是在1,2,3,⋯,n单位排列的基础上交换任意一对相邻的数字.
此时排列一定有n−2个自环和1个二元置换组成,并且这个二元置换里两个元素只差1.
一次交换操作可以造成两种效果
- 把一个大环拆成两个小环.
- 把两个小环合并成一个大环.
所以我们可以处理出初始排列中的所有置换环,设共有m个环,每个环的长度为 c i c_i ci,令 s = ∑ i = 1 m ( c i − 1 ) s=\sum_{i=1}^{m}(c_i-1) s=∑i=1m(ci−1),则s就是把原排列变成1,2,3,⋯,n单位排列需要的交换次数.
- 如果初始排列是1,2,3,⋯,n单位排列,显然需要一次操作.
- 如果某个长度大于等于2的环中存在两个相邻的元素,则我们在拆这个存在相邻元素的环时可以最后留下一个相邻元素组成的二元环,所以答案为 s = ∑ i = 1 m ( c i − 1 ) − 1 s=\sum_{i=1}^{m}(c_i-1)-1 s=∑i=1m(ci−1)−1.
- 否则所有环中均不存在相邻元素,我们需要先把初始排列还原成单位排列然后任意交换一对相邻元素,答案为 s = ∑ i = 1 m ( c i − 1 ) + 1 s=\sum_{i=1}^{m}(c_i-1)+1 s=∑i=1m(ci−1)+1
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#define fir(i,a,b) for(int i=a;i<=b;i++)
typedef long long LL;
#define met(x) memset(x,0,sizeof x)
//#define read(x) scanf("%d",&x)
using namespace std;
typedef pair<int,int> PII;
const int N = 2e5+10;
int a[N];
bool st[N];
vector<int> ct[N];
int cnt=0;
int read()
{
char ch = getchar(); int x = 0, w = 1;
while (ch < '0' || ch>'9') { if (ch == '-')w = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + ch - '0';
ch = getchar(); }
return x*w;
}
int main()
{
//freopen("test.txt", "r", stdin);
int t=read();
while(t--)
{
int n=read();
met(st);
cnt=0;
for(int i=0;i<n;i++)ct[i].clear();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=n;i++)
{
if(st[i])continue;
for(int j=i;!st[j];j=a[j])
{
ct[cnt].push_back(j);
st[j]=true;
}
cnt++;
}
int fl=1,sum=0;
for(int i=0;i<cnt;i++)sort(ct[i].begin(),ct[i].end());
for(int i=0;i<cnt;i++)
{
sum+=ct[i].size()-1;
if(ct[i].size()>=2)for(int j=0;j+1<ct[i].size();j++)
{
if(ct[i][j+1]-1==ct[i][j])fl=-1;
}
}
//cout<<sum;
sum+=fl;
cout<<sum<<endl;
}
//freopen("CON", "r", stdin);
//system("pause");
return 0;
}