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;
}