【CF1154】题解

A

直接模拟即可。

B

对数组中的值进行排序去重。发现若去重之后的数组中有大于 3 个数时无解,因为无法找到一个点到数轴上四个点的距离均相等。若去重之后的数组中只有三个值,则判断中间的值是否到两边的值相等,若不相等,同理无解,相等则解为距离。若只有两个不同的值,若中点是整数,则答案为中点到左端点的距离,否则为两点之间的距离。若只有一个不同的值,则答案直接为 0。

C

首先去掉整周的情况,先统计出有多少个完整的周。剩下为出发日所在周和结束日所在周的情况。将这两周拼成一周(十四天),枚举出发的时间,计算通过当前的食物可以到达的最远距离,取最大值后加入答案贡献即可。

#include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) x.begin(),x.end()
#define cls(a,b) memset(a,b,sizeof(a))
#define debug(x) printf("x = %d
",x)
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int dx[]={0,1,0,-1};
const int dy[]={1,0,-1,0};
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
//const int maxn=
const double eps=1e-6;
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline ll sqr(ll x){return x*x;}
inline ll read(){
	ll x=0,f=1;char ch;
	do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
	do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
	return f*x;
}
/*--------------------------------------------------------*/

const int s[]={0,1,2,0,2,1,0};
int a,b,c;
ll ans;

void read_and_parse(){
	a=read(),b=read(),c=read();
	ans=min(a/3,min(b/2,c/2));
	a-=ans*3,b-=ans*2,c-=ans*2;
	ans*=7;
}

void solve(){
	int res=0;
	for(int i=0;i<7;i++){
		int ret=0,aa=a,bb=b,cc=c;
		for(int j=i;j<i+7;j++){
			if(s[j%7]==0){
				if(aa)--aa,++ret;
				else break;
			}else if(s[j%7]==1){
				if(bb)--bb,++ret;
				else break;
			}else{
				if(cc)--cc,++ret;
				else break;
			}
		}
		res=max(res,ret);
	}
	printf("%lld
",ans+res);
}

int main(){
	read_and_parse();
	solve();
	return 0;
}

D

贪心策略:在阳光下且油箱未满的时候,优先采用电平来供电,其他情况下优先采用太阳能供电。

#include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) x.begin(),x.end()
#define cls(a,b) memset(a,b,sizeof(a))
#define debug(x) printf("x = %d
",x)
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int dx[]={0,1,0,-1};
const int dy[]={1,0,-1,0};
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=2e5+10;
const double eps=1e-6;
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline ll sqr(ll x){return x*x;}
inline ll read(){
	ll x=0,f=1;char ch;
	do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
	do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
	return f*x;
}
/*--------------------------------------------------------*/

int n,b,a,now;
bool s[maxn];

void read_and_parse(){
	n=read(),b=read(),a=read(),now=a;
	for(int i=1;i<=n;i++)s[i]=read();
}

void solve(){
	for(int i=1;i<=n;i++){
		if(s[i]==1){
			if(b&&now<a){
				--b,++now;
			}else{
				if(now)--now;
				else return (void)printf("%d
",i-1);
			}
		}else{
			if(now)--now;
			else if(b)--b;
			else return (void)printf("%d
",i-1);
		}
	}
	printf("%d
",n);
}

int main(){
	read_and_parse();
	solve();
	return 0;
}

E

采用双向链表进行模拟整个过程,因为每个人会且仅会被选择一次,因此时间复杂度为 (O(n))

By wzj_xhjbk, contest: Codeforces Round #552 (Div. 3), problem: (E) Two Teams, Accepted, #
 #include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) x.begin(),x.end()
#define cls(a,b) memset(a,b,sizeof(a))
#define debug(x) printf("x = %d
",x)
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int dx[]={0,1,0,-1};
const int dy[]={1,0,-1,0};
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=2e5+10;
const double eps=1e-6;
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline ll sqr(ll x){return x*x;}
inline ll read(){
	ll x=0,f=1;char ch;
	do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
	do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
	return f*x;
}
/*--------------------------------------------------------*/

int n,k,a[maxn],d[maxn],tag[maxn],l[maxn],r[maxn];

bool cmp(int x,int y){return a[x]>a[y];}

void read_and_parse(){
	n=read(),k=read();
	for(int i=1;i<=n;i++)a[i]=read(),d[i]=i,l[i]=i-1,r[i]=i+1;// 0 ~ n+1
	sort(d+1,d+n+1,cmp);
}

void solve(){
	int clk=1;
	for(int i=1;i<=n;i++){
		if(tag[d[i]]!=0)continue;
		tag[d[i]]=clk;
		int pos=d[i],cnt=0,lb=0,rb=n+1;
		while(l[pos]&&cnt<k)pos=l[pos],tag[pos]=clk,++cnt;
		if(l[pos])lb=l[pos];
		pos=d[i],cnt=0;
		while(r[pos]<=n&&cnt<k)pos=r[pos],tag[pos]=clk,++cnt;
		if(r[pos]<=n)rb=r[pos];
		r[lb]=rb,l[rb]=lb;
		clk=clk==1?2:1;
	}
	for(int i=1;i<=n;i++)printf("%d",tag[i]);
	puts("");
}

int main(){
	read_and_parse();
	solve();
	return 0;
}

F

不考虑优惠策略,可以发现买 k 个物品的最小值即为所有物品中的前 k 小值之和,因此按照物品的价格进行排序。现在考虑优惠政策,设 (dp[i]) 表示买 i 个物品的最小值,则状态转移方程为 (dp[i]=min{dp[i],dp[i-a]+sumlimits_{i=i-a+b+1}^{n}cost[i] })。其中求和部分可以利用前缀和预处理,时间复杂度为 (O(k*m))

#include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) x.begin(),x.end()
#define cls(a,b) memset(a,b,sizeof(a))
#define debug(x) printf("x = %d
",x)
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int dx[]={0,1,0,-1};
const int dy[]={1,0,-1,0};
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=2e5+10;
const double eps=1e-6;
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline ll sqr(ll x){return x*x;}
inline ll read(){
	ll x=0,f=1;char ch;
	do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
	do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
	return f*x;
}
/*--------------------------------------------------------*/

int n,m,k,a[maxn];
ll dp[2010],sum[2010];
P off[maxn];

void read_and_parse(){
	n=read(),m=read(),k=read();
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1;i<=m;i++)off[i].fi=read(),off[i].se=read();
	sort(a+1,a+n+1),sort(off+1,off+m+1);
}

void solve(){
	for(int i=1;i<=k;i++)sum[i]=sum[i-1]+a[i],dp[i]=sum[i];
	for(int i=1;i<=k;i++){
		for(int j=1;j<=m;j++){
			if(off[j].fi>i)break;
			dp[i]=min(dp[i],dp[i-off[j].fi]+sum[i]-sum[i-off[j].fi+off[j].se]);
		}
	}
	printf("%lld
",dp[k]);
}

int main(){
	read_and_parse();
	solve();
	return 0;
}

G

玄学复杂度。。考虑枚举 (gcd),每次找到序列中最小的两个数,计算最小公倍数与最优解进行比较即可。

原文地址:https://www.cnblogs.com/wzj-xhjbk/p/10724177.html