CF987
A
link
由于它是由递减变成递增的,所以一定是中间一段连续的相同数不变,前面变,后面变,因为对于一个数来说原来这些数前面的数都大于等于它,而现在都要小于等于它,而原来后面的数都小于等于它,而现在都大于等于它了,那么它左右等于它的就可以不变,而不等于它的就一定要变。
那么一定是找个数最多的数不变,其他的变。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n;
int h[55];
int cnt[55];
int ans;
void qwq(){
memset(cnt,0,sizeof(cnt));
ans = 0;
cin >> n;
for(int i = 1;i <= n;++ i){
cin >> h[i];
cnt[h[i]]++;
if(cnt[h[i]] > ans) ans = cnt[h[i]];
}
cout << n-ans << endl;
}
signed main(){
int t;
cin >> t;
while(t--) qwq();
return 0;
}
B
link
如果这个数的位置和它应在的位置相差大于\(1\),就一定换不过去。因为对于一个数\(i\),它只能和\(i-1\)和\(i+1\)换,那么它最多换两次(和\(i-1\)和\(i+1\)各一次),而且如果它换了两次,如果它往后换,一定会把\(i-1\)和\(i+1\)都换到它前面,如果往前换,一定会把\(i-1\)和\(i+1\)都换到它后面,这两种情况都无法满足它们三个按顺序排列且\(i\)在它该在的位置上。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n;
int p[200005];
void qwq(){
cin >> n;
for(int i = 1;i <= n;++ i)
cin >> p[i];
for(int i = 1;i <= n;++ i)
if(abs(p[i]-i) >= 2){
cout << "NO\n";
return;
}
cout << "YES\n";
}
signed main(){
int t;
cin >> t;
while(t--) qwq();
return 0;
}
C
link
对于偶数来说,我们只要\(1,1,2,2,3,3,4,4……\)这样放即可,这样两个一样的位置差是\(1\),是完全平方数,合法。
那么奇数怎么办呢?我们可以发现,最小的放三个使得第一二个位置的差和第二三个位置的差和第一三个位置的差都是完全平方数的是\(9+16=25(3^2+4^2=5^2)\)那么我们就可以让第一、十、二十六个位置是一样的,这是我们发现第一个和第十个中间是偶数个数,可以按偶数的方式放,但是第十个和第二十六个中间是奇数个数,需要找一个和后面的配对(不能和第十个和第二十六个中间的配对,因为那样剩下的还是奇数个),也就是找一个和第二十七个配对,使得第十个到它和它到第二十六个都是偶数个数,并且它和二十七的差还是完全平方数,那么我们就找\(2^2=4\)即可,找第二十三个和第二十七个配对即可。剩下的按偶数个数的放。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n;
int a[200005];
void qwq(){
cin >> n;
if(n%2 == 0){
for(int i = 1;i <= n;++ i)
cout << (i+1)/2 << " ";
cout << endl;
}
if(n%2 == 1){
if(n < 27) cout << -1 << endl;
else{
memset(a,0,sizeof(a));
a[1] = a[10] = a[26] = 1;
a[23] = a[27] = 2;
int gs = 0,cnt = 3;
for(int i = 1;i <= n;++ i){
if(a[i]) continue;
a[i] = cnt;
gs++;
if(gs == 2){
cnt++;
gs = 0;
}
}
for(int i = 1;i <= n;++ i)
cout << a[i] << " ";
cout << endl;
}
}
}
signed main(){
int t;
cin >> t;
while(t--) qwq();
return 0;
}
D
link
首先我们观察样例可以发现在最大值后面的一定可以跳到最大值,因为它可以跳到前面比它大的位置。
而且我们还可以发现,如果一个值比最大值后面的某个数大,那么他可以先跳到最大值后面那个比它小的,也就是可以跳到最大值后面的最小值,再跳到最小值。
那么我们从大到小枚举值域。 每次这个数如果大于前一个数中的最小值,就可以先跳到那个最小值,再跳到最大值。如果小于那么从这个数到上一个最大值的位置就只能跳到这个数了。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n;
int a[500005];
int ans[500005];
map<int,int> l;//数字i第一次出现的位置
int pre[500005];//前i个的前缀最大值
void qwq(){
l.clear();
scanf("%d",&n);
for(int i = 1;i <= n;++ i){
scanf("%d",&a[i]);
if(l[a[i]] == 0) l[a[i]] = i;
pre[i] = max(pre[i-1],a[i]);
}
int r = n;
int limit = n+1,noans = n+1;
for(int i = n;i >= 1;-- i){
if(l[i] == 0||l[i] > r) continue;
if(i <= limit){
limit = i;
noans = pre[l[i]];
}
for(int j = l[i];j <= r;++ j){
ans[j] = noans;
limit = min(limit,a[j]);
}
r = l[i]-1;
}
for(int i = 1;i <= n;++ i)
printf("%d ",ans[i]);
printf("\n");
}
signed main(){
int t;
cin >> t;
while(t--) qwq();
return 0;
}