USACO 2024 Feb bronze

挖个坑,今天晚上完成三篇手工翻译。awa

T1 Palindrome Game

赛时 100分

经典博弈论。手动枚举一下,很容易发现规律,当 S 为 10 的倍数时,先手输。
手动枚举需注意,不会证明你先别急,枚举要多,才能得出普遍规律(这个傻逼比赛刚开始一直打的是,当 S 为时 10 先手输)。

需要注意的是 S 的非常大。

T2 Milk Exchange

赛时 93.75分

简要题意,有一群奶牛,她们和相邻的牛交换牛奶,但是奶牛拿不了那么多牛奶。有些牛奶可能在交换的过程中浪费了。求交换 m 轮后剩余的牛奶。

如果把奶牛们传牛奶的过程抽象一张图的话,如下图(以样例以为例子)。我们很容易可以发现 1 .当这张图是一条链时,牛奶不会浪费。 2. 当两个点单独形成环的时候,牛奶不会浪费。 3. 当两个点形成环且环链接着链时,牛奶会发成浪费。

需要注意:牛奶不是无限多的,数据范围。

赛时代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6;
int n,m,a[N],k[N],s=0;
int pre[N];
char c[N];

int work(int x,int last){
	///if(pre[x]==last) return a[x];
	if(x==-1) return 0;
	return a[x]+work(pre[x],x);
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>c[i];
	for(int i=1;i<=n;i++) cin>>a[i],s+=a[i];
	memset(pre,-1,sizeof(pre));
	for(int i=1;i<=n;i++){
		if(c[i]=='L'){
			if(pre[i]!=i-1) pre[i-1]=i;
			k[i-1]++;
			k[i]--;
		}
		if(c[i]=='R'){
			if(pre[i]!=i+1) pre[i+1]=i;
			k[i+1]++;
			k[i]--;
		}
	} 
	if(pre[1]==0) pre[1]=n;
	if(pre[n]==0) pre[n]=1;  
	k[n]+=k[0];
	k[1]+=k[n+1];   			
	int ans=0;
	for(int i=1;i<=n;i++){
		if(k[i]>0){
			int maxx=work(i,0)-a[i];
			k[i]*=m;
			ans+=min(k[i],maxx);
		} 
	} 
	cout<<s-ans;
	return 0;
}

debug细节处理有误。

订正代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6;
int n,m,a[N],k[N],s=0;
int pre[N];
char c[N];

int work(int x,int last){
	if(x==-1) return 0;
	return a[x]+work(pre[x],x);
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>c[i];
	for(int i=1;i<=n;i++) cin>>a[i],s+=a[i];
	memset(pre,-1,sizeof(pre));
	for(int i=1;i<=n;i++){
		if(c[i]=='L'){
			if(pre[i]!=i-1) pre[i-1]=i;
			k[i-1]++;
			k[i]--;
		}
		if(c[i]=='R'){
			if(pre[i]!=i+1) pre[i+1]=i;
			k[i+1]++;
			k[i]--;
		}
	} 
	if(pre[0]==1) pre[n]=1;
	if(pre[n+1]==n) pre[1]=n;  
	k[n]+=k[0];
	k[1]+=k[n+1];   			
	int ans=0;
	for(int i=1;i<=n;i++){
		if(k[i]>0){
			int maxx=work(i,0)-a[i];
			k[i]*=m;
			ans+=min(k[i],maxx);
		} 
	} 
	cout<<s-ans;
	return 0;
}

T3 Maximizing Productivity

赛时分数 23.53分

题意感觉比较容易让人混淆,反正比赛的时候我是读了很多很多遍。
简要题意:已知 \(c_i\)\(t_i\) ,多次询问给你 s 和 v。问是否有至少 v 个 i 满足 s + \(t_i\) < \(c_i\)

暴力的做法,很简单。每次询问都遍历一边,统计符合条件的 i 即可。时间复杂度 O(nQ) 。 1≤Q≤2⋅105 ,1≤N≤2⋅105 。这个数据范围显然是难以通过的。

考虑怎么优化。首先 \(t_i\),\(c_i\) 都是常量,只有s是遍历。 求有多少个 v 个 i 满足 s < \(c_i\) - \(t_i\)(s + \(t_i\) < \(c_i\)→ s < \(c_i\) - \(t_i\))。
以此我们可以根据 \(c_i\) - \(t_i\) 对各个农场进行排序。最后二分查找第一个大于 \(c_i\) - \(t_i\) > s 的农场。即可求出满足条件的农场。

赛时代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e6;
int n,q,k[N];
int v,s,jsq;
struct code{
	int c,t,k;
}a[N];
int main(){
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++) scanf("%d",&a[i].c);
	for(int i=1;i<=n;i++) scanf("%d",&a[i].t);
	
	for(int p=1;p<=q;p++){
		scanf("%d%d",&v,&s);
		jsq=0;
		for(int i=1;i<=n;i++){
			if(s+a[i].t>=a[i].c) continue;
			jsq++;
		}
		if(jsq>=v) printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}


需要注意数据范围。

posted @ 2024-02-20 08:41  Wh1sky  阅读(63)  评论(0编辑  收藏  举报