Educational Codeforces Round 109 (Rated for Div. 2) A~E (VP)

A. Potion-making
在这里插入图片描述
要达成一定的配比,考虑最坏情况k和100-k,然后分别除以最小公因子的和便是答案(2min)

void solve(){
	cin>>k;
	int x=k,sum=100;
	sum-=x;
	int d=gcd(x,sum);
	print(x/d+sum/d);
}

B. Permutation Sort


直接分类讨论即可,最大值最小值的位置,如果有序是0,如果最大值或者最小值在自己的位置上是1,如果都不在但是最大值和最小值都在中间是2,否则如果最大值在1最小值在n位3(3min)

void solve(){
	n=read();rep(i,1,n) a[i]=read();
	if(check()) print(0);
	else if(n==a[n]||1==a[1]) print(1);
	else if(n==a[1]&&1==a[n]) print(3);
	else print(2);
}

C. Robot Collisions
在这里插入图片描述
机器人向左或者向右,距离位偶数的一定会相遇,但是遇到第一个会爆炸。这道题和USACO的一道题很像,用栈来模拟,因为距离有奇偶数影响,所以分别存一个奇数栈和偶数栈,然后先排序然后顺序扫描的时候所有R入栈,然后L和最近的R匹配。如果栈空则L入栈,这样说明了一段时间后其会变成对应的最小的向右元素。全部结束后如果栈还未空则两两配对。
思维难度有一点,写起来也有细节 (40min)

#define int LL
const int N=300010,M=N*2,mod=1e9+7;
int n,m,k;//,a[N],b[N];
string p;
struct Rob{
	int x,v,id;
}a[N];
stack<Rob> J,O;
int ans[N];

int calc(Rob A,Rob B){
	if(A.v==B.v){
		if(A.v==1) return (m-A.x+m-B.x)/2;
		else return (A.x+B.x)/2;
	}
	else{
		if(A.x>B.x) swap(A,B);
		if(A.v==1) return (B.x-A.x)/2;
		else return (m-B.x+A.x+m)/2;
	}
}

void solve(){
	while(J.size()) J.pop(); while(O.size()) O.pop();
	n=read(),m=read();
	rep(i,1,n) ans[i]=-1;
	rep(i,1,n) a[i].x=read(),a[i].id=i;
	rep(i,1,n){
		char op[2];
		scanf("%s",op);
		if(*op=='L') a[i].v=-1;else a[i].v=1;
	}
	
	sort(a+1,a+1+n,[](Rob &A,Rob &B){
		return A.x < B.x;
	});
	
	for(int i=1;i<=n;++i){
		if(a[i].v==1){ 
			a[i].x%2==0?O.push({a[i].x,a[i].v,a[i].id}):J.push({a[i].x, a[i].v,a[i].id});
		}
		else
			if(a[i].x%2==0){
				if(O.size()) ans[O.top().id]=ans[a[i].id]=calc(O.top(), a[i]),O.pop();
				else O.push(a[i]);
			}
			else{
				if(J.size()) ans[J.top().id]=ans[a[i].id]=calc(J.top(), a[i]),J.pop();
				else J.push(a[i]);
			} 
	}
	
	while(J.size()>1) {
		auto a=J.top();J.pop();
		auto b=J.top();J.pop();
		ans[a.id]=ans[b.id]=calc(a,b);
	}while(O.size()>1) {
		auto a=O.top();O.pop();
		auto b=O.top();O.pop();
		ans[a.id]=ans[b.id]=calc(a,b);
	}
	rep(i,1,n) printf("%d ",ans[i]);
	puts("");
}

D. Armchairs

怀疑和C弄反了…这道题我先贪心的WA了一发,后来发现不管数据范围真的很蠢。看到数据范围就5000一定是一个二维的DP,然后就想到了先把所有有人的位置搞出来,然后f[i][j]表示前i个有人的位置在j个位置里变换,没有一个原来有人的位置变换后有人的最小代价(15min)
状态转移方程:

f[i][j] = f[i-1][j];
if(!st[i]) f[i][j]=min(f[i][j], f[i-1][j-1]+abs(j-b[i])

直接看代码:

#define int LL
const int N=5010,M=N*2,mod=1e9+7;
int n,m,k,a[N],b[N],idx,f[N][N];
bool st[N];

void solve(){
	memset(f,0x3f,sizeof f);
	n=read();
	rep(i,1,n) {st[i]=read();if(st[i]) b[++idx]=i;}
	rep(i,0,n) f[0][i]=0;
	for(int i=1;i<=idx;++i){
		for(int j=1;j<=n;++j){
			f[i][j]=f[i][j-1];
			if(!st[j]) 
				f[i][j]=min(f[i][j], f[i-1][j-1]+abs(j-b[i]));
		}
	}
	int ans=mod;
	for(int i=1;i<=n;++i) ans=min(ans, f[idx][i]);
	print(ans);
}

E. Assimilation IV (补题)
在这里插入图片描述
大意就是n个城市m个点,每个城市和点之间都有距离。然后距离<=n+1,第i轮随机选择一个城市占领所有距离城市<=i的点,问占领的点的数量的期望

首先我们并不好直接求哪些城市被占领了,被占领的权重又是多少,因为这样需要枚举所有状态数(NP
因此我们考虑每一轮选点有哪些点不能被选到,这样逆向减去就是最终答案了。

学了一种比较巧妙地写法:

const int N=200010,M=N*2,mod=998244353;
int n,m,dist[N][25],fact;
/*算出不能控制的纪念碑的期望,然后总数减去便是答案*/
void solve(){
	fact=1;
	n=read(),m=read();
	for(int i=1,x;i<=n;++i){
		fact=1ll*fact*i%mod;  //所有情况数
		rep(j,1,m) x=read(),dist[j][x]++;  //统计距离每个点x长度的数量
	}
	int ans=0;
	for(int i=1;i<=m;++i){ //依次计算分子
		int tmp=1,tot=0;
		for(int j=n;j;--j){ //从第n个操作开始枚举
			tot += dist[i][j+1]; 
			tmp=1ll*tmp*tot%mod;
			tot -= 1; //被选择了一个点
		}
		ans=(1ll*fact-tmp+mod+ans)%mod;
	}
	ans=1ll*ans*fpower(fact,mod-2,mod)%mod;
	print(ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值