Codeforces Round #206 (Div. 1)

这场题目难度顺序估计出题人放错了,事实上我发的是A B C的解题报告。。。


A:

枚举最后拿走物品的位置。然后这个位置左边的只会是左手拿,右边的只会是右边拿。左右左右交替拿走即可,最后的物品可以左手拿也可以右手,取一下最小。再注意一下某一边没有物品之类的细节就可以写好代码了。


code:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
  
/*-------------------------Template----*/
#define N  100010 
#define E  50000
#define ll long long
#define CUBE(x) ((x)*(x)*(x))
#define SQ(x)     ((x)*(x))
#define ALL(x)     x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
#define maxAry(a,n) max_element(a,a+(n))
#define minAry(a,n) min_element(a,a+(n))
typedef pair<int,int> PI;
const int INF=0x3fffffff;
const int PRIME =999983;
const int MOD   =10007;
const int MULTI =1000000007;
const double EPS=1e-9;
/*----------------------end Template----*/

int a[N];
ll L[N],R[N];
int n,l,r,ql,qr;


int main()
{
	
	scanf("%d%d%d%d%d",&n,&l,&r,&ql,&qr);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++) L[i]=L[i-1]+a[i]*l;
	R[n+1]=0;
	for(int i=n;i>=1;i--) R[i]=R[i+1]+a[i]*r;
	ll ans=-1;
	for(int i=1;i<=n;i++){
		int len=min(i-1,n-i);
		ll sum=L[i-1]+R[i+1];
		if(len==i-1){
			int x=n-i-len-1;
			if(x!=-1) sum+=x*qr+min(a[i]*l,a[i]*r+qr);
			else sum+=min(a[i]*l,a[i]*r);
		}else{
			int x=i-1-len-1;
			if(x!=-1) sum+=x*ql+min(a[i]*l+ql,a[i]*r);
			else sum+=min(a[i]*l,a[i]*r);
		}
		if(ans==-1) ans=sum;
		else ans=min(ans,sum);
	}
	printf("%I64d\n", ans);
    return 0;
}


C:

     这题也是枚举,先枚举一个答案。然后我们需要检测下答案是否合法。对于一个答案x,要检测它是否合法,我们只需要看看是否所有数都能变成x的倍数。

     我们可以给数组排序,对于每一个[tx,(t+1)x]区间(t是正整数),二分找到最接近(t+1)x的数a。然后看a-tx是否小于等于k,如果满足,那么落在这个区间里的数都能变成x的倍数,否则直接return false。如果有元素小于x,那么也是不成立的。

     不过我的代码不是用上述方法做的,这是一开始想的拙计做法。上述的复杂的是O( (ln(m+1)+c)mlogn ),c是欧拉常数,m是枚举答案的上限,n是元素个数。而接下来说的方法是O( (ln(m+1)+c)m )

     本质还是要判断所有数能否搞成x的倍数。对于一个元素y,它的变化区间是[y-k,y],如果存在tx落在这个区间里,说明y是能变成符合要求的数。于是我们先区间覆盖一下(被覆盖的地方会加1),然后统计所有tx。如果统计结果恰好等于n,说明任意元素都符合要求。还要注意一个细节,就是枚举答案的下界必须是k+2,因为这样才能保证你不会统计重复的元素。理由很简单,区间[y-k,y],长度是k+1。如果你的x>=k+2,那么你当前tx落在区间里,(t+1)x肯定会跳出这个区间,所以就不会统计重复了。具体看看代码吧。小于k+2的必然能符合要求,理由可以自己想想。


code:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
  
/*-------------------------Template----*/
#define N  1000010 
#define E  50000
#define ll long long
#define CUBE(x) ((x)*(x)*(x))
#define SQ(x)     ((x)*(x))
#define ALL(x)     x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
#define maxAry(a,n) max_element(a,a+(n))
#define minAry(a,n) min_element(a,a+(n))
typedef pair<int,int> PI;
const int INF=0x3fffffff;
const int PRIME =999983;
const int MOD   =10007;
const int MULTI =1000000007;
const double EPS=1e-9;
/*----------------------end Template----*/

int n,k,a[N],cov[N];

int main()
{
	scanf("%d%d",&n,&k);
	for(int i=0;i<n;i++){
		scanf("%d",&a[i]);
		cov[a[i]+1]--;
		cov[max(1,a[i]-k)]++;
	}
	int m=*maxAry(a,n);
	for(int i=1;i<N;i++) cov[i]+=cov[i-1];
	for(int div=*minAry(a,n);div>=k+2;div--){
		int cnt=0;
		for(int i=1;i*div<=m;i++) cnt+=cov[i*div];
		if(cnt==n){
			printf("%d\n", div);
			return 0;
		}
	}
	printf("%d\n", min(k+1,*minAry(a,n)));
    return 0;
}


E:

     暴力枚举6个数字在相同位上的幸运数字组成。就是说看一下6个数字的个位由几个7,几个4,几个0组成这样,然后继续推十位,一直推下去。

比如42,答案7 7 7 7 7 7, 那个位就是由6个7组成。搜出解后可以根据每一位的组成推出6个数字。


code:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
  
/*-------------------------Template----*/
#define N  1000010 
#define E  50000
#define ll long long
#define CUBE(x) ((x)*(x)*(x))
#define SQ(x)     ((x)*(x))
#define ALL(x)     x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
#define maxAry(a,n) max_element(a,a+(n))
#define minAry(a,n) min_element(a,a+(n))
typedef pair<int,int> PI;
const int INF=0x3fffffff;
const int PRIME =999983;
const int MOD   =10007;
const int MULTI =1000000007;
const double EPS=1e-9;
/*----------------------end Template----*/

ll n;
int bit[20],m;
bool tag;
vector<PI > d[10],ans;

void dfs(int p,int x)
{
	if(p==m){
		if(!x){
			tag=false;
			ll res[6]={0},base=1;
			for(int i=0;i<ans.size();i++,base*=10){
				int a=ans[i].first, b=ans[i].second;
				for(int j=0;j<6;j++){
					if(a) res[j]+=4*base, a--;
					else if(b) res[j]+=7*base, b--;
				}
			}
			for(int i=0;i<6;i++)
				printf("%I64d ", res[i]);
			puts("");
		}
		return ;
	}
	int y=(bit[p]-x+10)%10;
	for(int i=0;tag && i<d[y].size();i++){
		ans.push_back(d[y][i]);
		int a=d[y][i].first, b=d[y][i].second;
		dfs(p+1,(x+a*4+b*7)/10);
		ans.pop_back();
	}
}

int main()
{
	int re;
	for(int i=0;i<=6;i++)
		for(int j=0;i+j<=6;j++)
			d[(i*4+j*7)%10].push_back((PI){i,j});
	scanf("%d",&re);
	while(re--){
		scanf("%I64d",&n);
		m=0;
		while(n)
			bit[m++]=n%10, n/=10;
		tag=true;
		dfs(0,0);
		if(tag) puts("-1");
	}
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值