这场题目难度顺序估计出题人放错了,事实上我发的是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;
}