Codeforces Round #301 (Div. 2)——A.B.C.D.E

A. Combination Lock
有两种旋转方式

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    cin>>n;
    string s1,s2;
    cin>>s1>>s2;
    int ans=0;
    int a,b;
    for(int i=0;i<n;++i){
        a=min(s1[i]&0xf,s2[i]&0xf);
        b=max(s1[i]&0xf,s2[i]&0xf);
        ans+=min(b-a,a+10-b);
    }
    cout<<ans<<endl;
    return 0;
}

B. School Marks
n个作业,k个已完成,每个作业能得到的最高分,所有作业的总分不能超过x,所有作业分数的中位数为y

k个已完成作业的得分

分析:
对于已完成的作业:
总分为sum,小于y的个数为low,大于等于y的个数为high。

1.sum+n-k>x 不可能
2.当且仅当high>=(n+1)/2 ,所以对于已完成作业部分,low>=(n+1)/2,则不可能
3.优先填充y使得high==(n+1)/2,剩余的用1填

#include <bits/stdc++.h>
const int MAXN=1010;
using namespace std;
int a[MAXN];
int main()
{
    int n,k,p,x,y,z;
    int sum=0;
    int mx=0,mi=0,mid=0;
    scanf("%d%d%d%d%d",&n,&k,&p,&x,&y);
    for(int i=0;i<k;++i){
        scanf("%d",&z);
        sum+=z;
        if(z==y) mid++;
        if(z>y) mx++;
        if(z<y) mi++;
    }
    if(sum+n-k>x) puts("-1");
    else{
        k=n-k;
        int cnt=0;
        while(k--){
            if(mid+mx<(n+1)/2){
                mx++;
                a[cnt++]=y;
                sum+=y;
            }else{
                mi++;
                a[cnt++]=1;
                sum+=1;
            }
        }
        if(sum>x||mid+mx<(n+1)/2) puts("-1");
        else{
            for(int i=0;i<cnt;++i){
                cout<<a[i]<<" ";
            }
            cout<<endl;
        }
    }
    return 0;
}

C. Ice Cave
有一个n*m的冰面,每个格子都是一个冰块。’.’表示完整的冰,’X’表示破裂的冰,当人走到完整的冰,那么这块冰就会变成破裂的冰;当人走到破裂的冰,人就会从这块冰的位置fall down

给定人的初始位置,一定为’X’,和终点位置,判断人能不能走到终点位置fall down

假定人走到了位置(x,y),如果从该点继续搜下去走并不能完成目标,那么就不用回溯了。前面走过了为什么要再走一遍呢?

#include <bits/stdc++.h>
const int MAXN=550;
using namespace std;
char mp[MAXN][MAXN];
int sx,sy,ex,ey;
int n,m;
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
bool isok(int x,int y){
    if(x>=0&&x<n&&y>=0&&y<m) return true;
    return false;
}
bool dfs(int x,int y){
    mp[x][y]='X';
    for(int i=0;i<4;++i){
        int tx=x+dx[i];
        int ty=y+dy[i];
        if(isok(tx,ty)){
            if(mp[tx][ty]=='X'){
                if(tx==ex&&ty==ey) return true;
            }
            else{
                if(dfs(tx,ty)) return true;
            }
        }
    }
    return false;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.cpp","r",stdin);
#endif // ONLINE_JUDGE
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;++i){
        scanf("%s",mp[i]);
    }
    scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
    sx--;sy--;ex--;ey--;
    if(dfs(sx,sy)) puts("YES");
    else puts("NO");
    return 0;
}

D. Bad Luck Island
概率dp?

E. Infinite Inversions

有一个无限长的序列,有n次的交换操作,每次交换两个位置的数。求最后该序列的逆序数。

分析:
由于交换的数的范围是1e9,先将操作数离散化。
对于离散化后的序列,对于每一个位置,求出它的逆序数和缺少的数,全部相加就为总和

例如:

6 2 3 4 5 1 7 8 9 。。。

1原来的位置是1,现在变为了6,那么1~6这段区间中间的数提供的逆序数为1~6区间没有出现过的数的个数,因为对于要操作的数,我们是具体算的,没有出现的数是附加的。
不管是原来很大的数放到了比原先小的位置,还是原先很小的数放到了很大的位置,都要加上改变前后这段区间内没有出现过的数的个数(有多少个数比它小 或者 有多少个数比它大)

#include <bits/stdc++.h>
typedef long long LL;
const int MAXN = 200020;
using namespace std;
int n,num;
int x[MAXN],val[MAXN],sum[MAXN];
int c[MAXN];
struct node{
    int x,y;
}a[MAXN];
void update(int p){
    for(int i=p;i>0;i-=i&-i){
        c[i]+=1;
    }
}
int get_sum(int p){
    int res=0;
    for(int i=p;i<MAXN;i+=i&-i){
        res+=c[i];
    }
    return res;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%d%d",&a[i].x,&a[i].y);
        x[++num]=a[i].x;
        x[++num]=a[i].y;
    }
    sort(x+1,x+num+1);
    num=unique(x+1,x+num+1)-x-1;
    for(int i=1;i<=num;++i) val[i]=x[i];
    for(int i=1;i<=num;++i) sum[i]+=sum[i-1]+x[i]-x[i-1]-1;
    for(int i=1;i<=n;++i){
        int l=lower_bound(x+1,x+num+1,a[i].x)-x;
        int r=lower_bound(x+1,x+num+1,a[i].y)-x;
        swap(val[l],val[r]);
    }
    LL ans=0;
    for(int i=1;i<=num;++i){
        int pos=lower_bound(x+1,x+num+1,val[i])-x;
        ans+=(LL)get_sum(pos);
        ans+=(LL)abs(sum[pos]-sum[i]);
        update(pos);
    }
    cout<<ans<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值