CodeForces - 1256B *
给出n个数,每个位置i只能交换一次,交换i和i+1位置,故一共n-1次,求得按字典序排得的最小数列
#include <bits/stdc++.h>
using namespace std;
int const N=105;
int t,n;
int a[N],vis[N];
int main()
{
scanf("%d",&t);
while(t--)
{
memset(a,0,sizeof(a));
memset(vis,0,sizeof(vis));
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
int p=0;
while(a[p]!=i)p++;
while(p>0&&!vis[p]&&a[p]<a[p-1])
{
swap(a[p],a[p-1]);
vis[p]=1;
p--;
}
}
for(int i=1;i<=n;i++)
{
printf("%d%c",a[i],i==n?'\n':' ');
}
}
return 0;
}
类似冒泡排序
CodeForces - 1256C *
给出m块的木板长,要求必须每块都用,并且按顺序铺在河面上,每次可以向前跳1到d格,跳到的地方必须有木板或是终点,问能否从0跳到n+1,图是别人的
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
const int N=2005;
const int mod=1e9+7;
int main()
{
std::ios::sync_with_stdio(false);
int n,m,d;
while(cin>>n>>m>>d)
{
int w[N],sum=0;
for(int i=1; i<=m; i++)
{
cin>>w[i];
sum+=w[i];
}
int s=0,t=1;
int ans[N];
memset(ans,0,sizeof(ans));
int flag=0;
while(s<=n)
{
if(s+d+sum<=n+1)
s+=d;
else
s=n+1-sum;
if(s>=n+1)
break;
if(t<=m)
{
for(int i=s; i<s+w[t]; i++)
{
ans[i]=t;
}
s=s+w[t]-1;
sum-=w[t];
t++;
}
else
{
flag=1;
break;
}
}
if(flag)
cout<<"NO"<<endl;
else
{
cout<<"YES"<<endl;
for(int i=1; i<=n; i++)
cout<<ans[i]<<" ";
cout<<endl;
}
}
return 0;
}
贪心,每一次都跳最远的d,模拟跳的过程,模拟过程中的位置s,剩余木板长度sum,要求恰巧到终点
贪心部分:当前位置+跳一次+剩余木板,看会不会跳过终点,不会就跳一次,过了就不跳;跳过终点推出贪心部分;同时跳的过程中对木板进行分配,每次赋值(木板长度-1)个。
CodeForces - 1256D
给出长度为n的一串二进制数,交换相邻的两位数k次,k次不一定要用完,次求交换后最小的数,
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <iomanip>
#define INF 0x3f3f3f3f
#define mod 2008
using namespace std;
string s;
int main()
{
int t;
cin>>t;
while(t--)
{
long long n,k;
cin>>n>>k;
cin>>s;
int j=0;
for (int i = 0; i < n; i++)
{
if (j < i) j = i;
while (j < n && s[j] != '0') j++;
if (j < n && j - i <= k)
{
swap(s[i], s[j]);
k -= j - i;
}
}
cout<<s<<endl;
}
return 0;
}
这题我当时没有做出来,题目里的每次交换相邻的目的是使0从左到右的第一个0 移到最左边,即直接交换第一个0与最左边一位,第二个0与第左边第二位……我没想到可以直接一步换到位并减去相应的步骤数而只一次次移动,无论怎么优化都会超时,因为目的是把第一个0移到最左边第一位,第二个0移到第左边第二位……所以可以直接对位数从左往右循环,找到第一个0直接与最左边的非零位交换,减去直接相差的位数,if (j < i) j = i;也是尤为重要的一步,如果已经移到最小的形式(0在左1在右)没有这一部可能会出现j<i的情况,导致交换位数,不是最小了
CodeForces - 1256E *
n个数,可分组,每组最少三个,每组的值为最大值减最小值,所有组的值的和为总值,求总值的最小值。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fi first
#define se second
const int maxn=1e6+5;
const int INF=0x3f3f3f3f;
ll n,q,f,flag;
ll dp[maxn],pre[maxn],ans[maxn];//dp[i]表示前i-1个人划分好后的最小d值和
string s,t;
struct node{
ll v;
ll p;
}a[maxn];
bool cmp(node a,node b){
return a.v<b.v;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].v;
a[i].p=i;
}
sort(a+1,a+n+1,cmp);
memset(dp,INF,sizeof dp);
dp[1]=0; //前0个 最小d之和
for(int i=1;i<=n;i++){
for(int j=2;j<=4 && i+j<=n;j++){
ll diff=a[i+j].v-a[i].v;
if(dp[i+j+1]>dp[i]+diff){
dp[i+j+1]=dp[i]+diff;
pre[i+j+1]=i; //i~i+j 相同组
}//记录方案,表示[i,i+j]这些人分为一组 i=4 p[7]=4 4-6 4
}
}
ll root=n+1,cnt=1;
while(root!=1){ //n~!0
for(int i=root-1;i>=pre[root];i--){//[p[root], root-1]这些人为同一组
ans[a[i].p]=cnt;
}
cnt++;
root=pre[root];
}
cout<<dp[n+1]<<" "<<cnt-1<<endl;
for(int i=1;i<=n;i++){
cout<<ans[i];
if(i!=n)
cout<<" ";
}
cout<<endl;
return 0;
}
多分组可以使值最小,每个组3~5人,dp[i]表示前i-1个人的最小值,枚举i+2到i+4之间的数,选择与a[i]的差最小的一个,i到这个数为一组
CodeForces - 1256F *
给出两个长度相等的字符串,多次翻转每个中相同长度,求是否可以通过多次操作使得两串相等
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+50;
char s[N],t[N];
int q,n,cnt[30];
int c[120];
int lowbit(int x){
return x&(-x);
}
void add(int i,int x){
while(i<=100){
c[i]+=x;
i+=lowbit(i);
}
}
int sum(int i){
int ans=0;
while(i){
ans+=c[i];
i-=lowbit(i);
}
return ans;
}
int main(){
scanf("%d",&q);
while(q--){
scanf("%d",&n);
scanf("%s",s+1);
scanf("%s",t+1);
memset(cnt,0,sizeof(cnt));
bool dou=false;
for(int i=1;i<=n;i++){
cnt[s[i]-'a']++;
if(cnt[s[i]-'a']>=2){
dou=true;
}
}
for(int i=1;i<=n;i++){
cnt[t[i]-'a']--;
}
bool flag=true;
for(int i=0;i<26;i++){
if(cnt[i]){
flag=false;
break;
}
}
if(!flag){
printf("NO\n");
}else{
if(dou){
printf("YES\n");
}else{
memset(c,0,sizeof(c));
int ss=0;
for(int i=1;i<=n;i++){
ss+=i-1-sum(s[i]-'a'+1);
add(s[i]-'a'+1,1);
}
memset(c,0,sizeof(c));
int tt=0;
for(int i=1;i<=n;i++){
tt+=i-1-sum(t[i]-'a'+1);
add(t[i]-'a'+1,1);
}
if(ss%2==tt%2){
printf("YES\n");
}else{
printf("NO\n");
}
}
}
}
return 0;
}
实质是相邻两个字符的交换,还不够理解