这场开局不顺。。A题都不会做。。。B题一直不知道他只能用2,3,5。。。然后就拙计。好在最后4题都是1A没有fst勉强前50。。E题最后十分钟写了乱交也没A,事实上有很多bug赛后才A的。
C:
题意:有三种材料做汉堡。他手头上已经有一些材料,同时他有一定的现金可以去买材料。求最多能做几个汉堡。
思路:二分答案
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;
#define N 100010
#define ALL(x) x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
typedef long long ll;
typedef pair<int,int> PI;
const int INF = 0x3fffffff;
const int MOD = 100000007;
const double EPS = 1e-7;
char s[N];
int cnt[16];
int p[16];
int need[16];
ll money;
bool check(ll num)
{
ll tot=0;
for(int i=0;i<3;i++){
tot+=1ll*max(num*need[i]-cnt[i],0ll)*p[i];
}
return tot<=money;
}
int main()
{
int a,b;
scanf("%s",s);
for(int i=0;i<3;i++) scanf("%d",&cnt[i]);
for(int i=0;i<3;i++) scanf("%d",&p[i]);
for(int i=0;s[i];i++){
if(s[i]=='B') need[0]++;
else if(s[i]=='S') need[1]++;
else need[2]++;
}
scanf("%I64d",&money);
ll l=0, r=money+1000;
while(l<r){
ll mid=(l+r)>>1;
if(check(mid)) l=mid+1;
else r=mid;
}
printf("%I64d\n",r-1);
return 0;
}
D:
题意:给你一层一层的水盆,从上往下,水满了会流到下面的水盆里。可以给某个水盆加水,同时也会询问某个水盆当前水的体积。注意一下,水盆的体积不一定递增,即便下面的水盆比上面的小,也能接到上面流下来的水。
思路:如果某个水盆装满了,那上面流下的水只会经过它再流到下面没满的水盆里。所以我们可以用链表维护,把满的水盆删掉。每个点最多被删一次,复杂度O(n)
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;
#define N 200010
#define ALL(x) x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
typedef long long ll;
typedef pair<int,int> PI;
const int INF = 0x3fffffff;
const int MOD = 100000007;
const double EPS = 1e-7;
int n,r[N];
bool vis[N];
ll vol[N],a[N],x;
void init()
{
for(int i=1;i<=n;i++)
r[i]=i+1;
CLR(vis,true);
}
int next(int i)
{
return vis[i] ? i : (r[i]=next(r[i]));
}
void erase(int s,int t)
{
s=next(s);
while(s<t){
ll Min=min(vol[s],x);
vol[s]-=Min;
x-=Min;
if(!vol[s]) vis[s]=false;
else return ;
if(!x) return ;
s=next(r[s]);
}
}
int main()
{
int m;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%I64d",&vol[i]);
a[i]=vol[i];
}
init();
scanf("%d",&m);
int op,p;
while(m--){
scanf("%d%d",&op,&p);
if(op==1){
scanf("%I64d",&x);
erase(p,n+1);
}else{
printf("%I64d\n",a[p]-vol[p]);
}
}
return 0;
}
E:
题意:n个站点,去掉一些,剩下k个站点。使得k个站点两两的距离和最小。
思路:排序后,答案显然是连续的k个站点。至于是哪连续k个,两个指针扫一下就好了,具体看代码。
比赛的时候排序完了,没有记录原始的位置,赛后才发现。。。
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;
#define N 300010
#define ALL(x) x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
typedef long long ll;
typedef pair<int,int> PI;
const int INF = 0x3fffffff;
const int MOD = 100000007;
const double EPS = 1e-7;
pair<ll,int> a[N];
int main()
{
int n,m;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%I64d",&a[i].first);
a[i].second=i;
}
sort(a+1,a+n+1);
scanf("%d",&m);
ll ans=0,sum=0,l=1;
for(int i=1;i<=m;i++){
ans+=(i-1)*a[i].first-sum;
sum+=a[i].first;
}
ll now=ans;
for(int i=m+1,j=1;i<=n;i++,j++){
sum-=a[j].first;
now+=(m-1)*a[i].first-sum - (sum-(m-1)*a[j].first);
if(now<ans){
ans=now;
l=j+1;
}
sum+=a[i].first;
}
for(int i=l;i<=l+m-1;i++) printf("%d ",a[i].second); puts("");
return 0;
}