A. Restoring Three Numbers
给出a+b, a+c, b+c a+b+c 顺序不固定,求a,b,c的值
没什么好说的,找到最大的数就是a+b+c,再减去其他三个数
#include<bits/stdc++.h>
using namespace std;
long long num[4];
int main()
{
long long a,b,c;
for(int i=0;i<4;i++)
scanf("%lld",&num[i]);
sort(num,num+4);
a=num[3]-num[0];
b=num[3]-num[1];
c=num[3]-num[2];
cout<<a<<' '<<b<<' '<<c<<endl;
}
B. Make Them Equal
给出一个序列,问是否存在d,对于序列每个数ai,进行+d,-d,或不变,使得序列所有数相等
由于ai<=100,直接暴力枚举
#include<bits/stdc++.h>
using namespace std;
int num[105];
int main()
{
int i,j,k,n,d;
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d",&num[i]);
}
for(d=0;d<=100;d++)
{
int p=num[0]+d;
for(i=1;i<n;i++)
if((abs(num[i]-p)!=d)&&(num[i]!=p))
break;
p=num[0]-d;
for(j=1;j<n;j++)
if((num[j]!=p)&&(abs(num[j]-p)!=d))
break;
p=num[0];
for(k=1;k<n;k++)
if((num[k]!=p)&&(abs(num[k]-p)!=d))
break;
if(i==n||j==n||k==n)
break;
}
if(d!=101)
printf("%d\n",d);
else
printf("-1\n");
}
C. Gourmet Cat
a,b,c三种食物,星期一,四,七吃a,星期二,六吃b,星期三,五吃c,每天吃一份食物,出发时间可以是任意天,求最大出行天数
一个星期a-=3,b-=2,c-=2;先算出能撑多少个星期,再枚举出发是星期几,求最大出行天数
#include<bits/stdc++.h>
using namespace std;
int main()
{
long long a,b,c;
long long a1,b1,c1;
long long num=0;
long long week,day,ans;
scanf("%lld%lld%lld",&a,&b,&c);
week=min(min(a/3,b/2),c/2);
day=week*7;
ans=day;
a-=week*3;
b-=week*2;
c-=week*2;
for(int i=1;i<=7;i++)
{
a1=a;
b1=b;
c1=c;
day=week*7;
for(int j=0;j<7;j++)
{
int k=(i+j)%7;
if(k==0)
k=1;
if(k==1||k==4||k==7)
{
if(a1>0)
day++,a1--;
else
break;
}
else if(k==2||k==6)
{
if(b1>0)
day++,b1--;
else
break;
}
else if(k==3||k==5)
{
if(c1>0)
day++,c1--;
else
break;
}
}
ans=max(day,ans);
}
printf("%lld\n",ans);
}
D. Walking Robot
一个机器人,有一块主能源和备用能源,每次前进一个单位消耗一个单位能源,当在太阳下使用主能源(主能源不为0)时,备用能源增加一个单位(备用能源不能超过初始值,主能源不能充电),求最大行进距离(0代表阴影区,1代表太阳下)
备用能源满时则用备用能源
备用能源不满时,在太阳下优先用主能源,在阴影下优先用主能源
#include<bits/stdc++.h>
const int N=2e5+7;
using namespace std;
int state[N];
int main()
{
int i,j,n,a,b,w=0;
int bmax;
scanf("%d%d%d",&n,&a,&b);
bmax=b;
for(i=0;i<n;i++)
scanf("%d",&state[i]);
for(i=0;i<n;i++)
{
if(a==0&&b==0)
break;
w++;
if(state[i]==1)
{
if(b!=bmax)
{
if(a!=0)
{
a--;
b++;
}
else
b--;
}
else
b--;
}
if(state[i]==0)
{
if(b!=0)
b--;
else
a--;
}
}
printf("%d\n",w);
}
E. Two Teams
两个球队教练轮流选队员,1号教练在球员中选出最优秀的球员,并且把该球员左边k个球员(不足k个则取完)和右边k个球员选入1队,接着2号教练在剩下的的球员中采用同样的操作,然后又是1号教练......问最后每个球员属于哪个队。
解法很多,有用并查集的,有用链表的,还有用线段树写的(比如说我队友,有点头铁),我是通过记录下一条的方法写的;
建立一个rk数组,记录能力值排名i的球员的下标位置,并且维护next数组,保存当该名球员已经被选中,应该跳向哪个位置数组的哪个位置
#include<bits/stdc++.h>
const int N=2e5+7;
using namespace std;
int state[N],rk[N],val[N];
int nx1[N],nx2[N];
//nx1往左下一跳
//nx1往右下一跳
int main()
{
int n,i,j,k,flag=0;
scanf("%d%d",&n,&k);
for(i=0;i<n;i++)
{
scanf("%d",&val[i]);
rk[n-val[i]]=i;
}
for(i=0;i<n;i++)
nx1[i]=i;
for(i=0;i<n;i++)
nx2[i]=i;
for(i=0;i<n;i++)
{
int id=rk[i];//排名i的数字下标
if(state[id]!=0)//被选了
continue;
if(flag==0)
state[id]=1;
else
state[id]=2;
int p=k;
int k1=1;
j = id;
while(p)
{
if(j-k1<0)
break;
if(state[j-k1]!=0)
{
k1=j-nx1[j-k1];
}
else
{
if(flag==0)
state[j-k1]=1;
else
state[j-k1]=2;
k1++;
p--;
}
}
int x=j-k1;//左边界
k1 = 1;
p = k;
j = id;
while(p)
{
if(j+k1>=n)
break;
if(state[j+k1]!=0)
{
k1=nx2[j+k1]-j;
}
else
{
if(flag==0)
state[j+k1]=1;
else
state[j+k1]=2;
k1++;
p--;
}
}
int y=j+k1;//右边界
nx1[y-1]=x;
nx2[x+1]=y;
flag++;
flag%=2;
}
for(i=0;i<n;i++)
printf("%d",state[i]);
printf("\n");
}
F. Shovels Shop
给出n个物品,从中购买k个物品,有m种优惠方案:(x1,y1),(x2,y2)......(xm,ym)代表当购买xi个物品时间,最便宜的yi个免费,求支付的最小价格。
被队友误导了,口胡成完全背包(没错,就是那个用线段树写E题的那个人),虽然的确是一道dp题
因为我们是取买k个最小的代价,那么我们只要用到最小的k个物品;进行dp之前有两个结论要证明
(1)对于优惠值为yi,若存在yi==yj && xi>xj,如果我们对p个数用过(xi,yi)方案,那么我们把相同y值的而x更小的方案(xi,yi)替换(xj,yj),剩下的xi-xj个数可以尝试选择优惠方案来减小代价,所以相同y值(xj,yj)比(xi,yi)更优
(2)对于排序好的p个数,使用两种方案(xi,yi),(xj,yj),xi+xj==p,取出p个数前面xi个使用优惠(xi,yi),再对剩下xj个数使用优惠(xj,yj)的代价( 设这里先用(xi,yi)再用(xj,yj)代价小于先用(xj,yj)再用(xi,yi) )小于取出中间xi个使用(xi,yi)优惠,再对剩下xj个使用(xj,yj)优惠的代价要低(大家可以自己推一下),由此递推出使用q种优惠也是每次取出最大的几个
接着我们预处理一下,求出对于每个y值,最小的x是什么,然后dp
#include<bits/stdc++.h>
const int N=2e5+7;
using namespace std;
int cost[N],a[N];
int dp[2005];
int main()
{
int i,j,n,m,k,p,ans=0;
int x,y;
scanf("%d%d%d",&n,&m,&k);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
sort(a+1,a+n+1);
n = k;
for(i=0;i<m;i++)
{
scanf("%d%d",&x,&y);
if(cost[y]==0)
cost[y]=x;
else
cost[y]=min(cost[y],x);
}
dp[0]=0;
for(i=1;i<=n;i++)
dp[i]=dp[i-1]+a[i];
for(i=1;i<=n;i++)//取出前i个的数的最小代价
{
for(j=0;j<=i;j++)
{
x=cost[j];
y = j;
//取出后面x个数,最小的y的免费
p = 0;
if(x>i)
continue;
for(k=i-(x-y)+1;k<=i;k++)
p+=a[k];
dp[i]=min(dp[i],dp[i-x]+p);
}
}
cout<<dp[n]<<endl;
}
G. Minimum Possible LCM
求n个数中哪两个数的最小公倍数最小,先上图。。。
我可能连傻逼都不如吧。。。
按照cls的说法枚举gcd,时间复杂度为n+n/2+n/3+.....n/n-1+n/n ≈ n*logn,高数学的差,调和级数都不会算,还以为是O(n^2)
用两个数组存放值为ai出现的第一个位置,和另一个位置(如果出现过两次及以上),然后就可以枚举了
#include<bits/stdc++.h>
const int N=1e7+7;
using namespace std;
int state[N];
int state1[N];
long long gcd(long long x,long long y)
{
if(y==0)
return x;
return gcd(y,x%y);
}
int main()
{
int i,j,x,n,Max=0,num=0;
int ans1,ans2;
long long ans=0x3f3f3f3f3f3f3f3f;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&x);
if(state[x]==0)
state[x]=i;
else
state1[x]=i;
Max=max(Max,x);
}
long long a,b;
for(i=1;i<=Max;i++)//枚举gcd
{
num = 0;
for(j=i;j<=Max;j+=i)//枚举最小倍数
{
if(state[j]!=0)
{
if(num==0)
a=j;
else
b=j;
num++;
}
if(state1[j]!=0)
{
b=j;
num=2;
}
if(num==2)
{
if(ans>a*b/gcd(a,b))
{
ans=a*b/gcd(a,b);
ans1=state[a];
ans2=state[b];
if(state1[b]!=0)
ans2=state1[b];
}
break;
}
}
}
if(ans1>ans2)
swap(ans1,ans2);
cout<<ans1<<' '<<ans2<<endl;
}