两个手柄只有一个充电器,不充电的手柄每分钟掉两格电,充电的手柄每分钟加一格电,一开始有一个手柄的电量是1的话那个手柄必须充电,当有一个手柄电量为0的时候游戏就停止了,简单的模拟。
#include<stdio.h>
int max(int a,int b)
{
if(a > b) return a;
else return b;
}
int min(int a,int b)
{
if(a < b) return a;
else return b;
}
int main()
{
int a,b;
int ans;
int l,h;
while(~scanf("%d%d",&a,&b))
{
ans=0;
l=min(a,b);
h=max(a,b);
int charge=1;
if(l<2 && h<2)
{
printf("0\n");
continue;
}
while(l>0 && b>0)
{
while(charge==1)
{
if(h==1||h==2)
{
charge=2;
break;
}
l++;
h-=2;
ans++;
}
while(charge==2)
{
if(l==1||l==2)
{
charge = 1;
break;
}
h++;
l-=2;
ans++;
}
if(h<=2&&l<=2)
{
ans++;
break;
}
}
printf("%d\n",ans);
}
return 0;
}
一个人喜欢的乐队是1-m,他想要他所有喜欢的乐队演出次数最少的那个值最大化。n表示有n首曲子要表演 a[i]表示要表演的乐队
n/m 先算出那个最小的数是多少
统计1-m的个数
大于m的数都替换掉
当然小于m但是表演次数大于n/m也要替换掉
#include<stdio.h>
#include<algorithm>
using namespace std;
#define N 2001
int a[N],b[N];
int main()
{
int n,m,l=0;
scanf("%d %d",&n,&m);
int rec = n / m;
for(int i=1 ; i<=n ; i++)
{
scanf("%d",&a[i]);
if(a[i] <= m)
b[a[i]]++;
}
//for(int i=1; i<=m ; i++)
// printf("%d ",b[i]);
//printf("\n");
for(int i=1 ; i<=m ; i++)
{
if(b[i] < rec)
l += rec - b[i];
}
for(int i=1 ; i<=n ; i++)
{
if(a[i] > m)
{
for(int j=1 ; j<=m ; j++)
{
if(b[j] < rec)
{
a[i] = j;
b[j]++;
break;
}
}
}
else if(b[a[i]] > rec){
for(int j=1 ; j<=m ; j++)
{
if(b[j] < rec)
{
b[a[i]]--;
b[j]++;
a[i] = j;
break;
}
}
}
}
printf("%d %d\n",rec,l);
for(int i=1 ; i<n ; i++)
printf("%d ",a[i]);
printf("%d\n",a[n]);
}
C Crossing River
n个人过河,只有一条船,一次只能装两个人,每次过去后还要一个人划回来,过河时间为两个人中速度慢的,求所有人过河最小的时间。
贪心,设a,b,c,d分别为最快,次快,次慢,最慢。那么把c,d送过河去有两种策略。
1. 最快和次快的先过去,最快回来,次慢和最慢过去,次快回来
时间为 b+a+d+b
2. 最快和次慢过去,最快回来,最快和最慢过去,最快回来
时间为 c+a+d+a
应该是每次都要让对岸速度最快的把船开回来,然后人数小于四的话可以直接求得结果的
emmm....其实我自己还是搞不懂这种题,对我来说好难理解。。。
#include<stdio.h>
#include<algorithm>
using namespace std;
#define N 1001
int a[N];
int max(int a,int b)
{
if(a > b) return a;
return b;
}
int main()
{
int t;
int n;
int sum1,sum2;
scanf("%d",&t);
while(t--)
{
sum1 = 0;
sum2 = 0;
scanf("%d",&n);
for(int i=1 ; i<=n ; i++)
scanf("%d",&a[i]);
sort(a+1,a+1+n);
for(; n>=4 ; n-=2)
{
sum2 += min(a[1] + a[n] + a[n-1] + a[1],a[2] + a[1] + a[n] + a[2]);
}
if(n == 1)
{
printf("%d\n",a[1]+sum2);
continue;
}
else if(n == 2)
{
printf("%d\n",a[2]+sum2);
}
else if(n == 3)
{
printf("%d\n",a[1]+a[2]+a[3]+sum2);
}
}
}
D Doing Homework again
有很多作业要做,每个作业都有一个截止时间,如果超过截止时间这个作业没做的话就会扣分,假设做每项作业要一天,问怎么安排才能减最少的分
结构体存下,用数组标记一下每天是否有作业做,按分数从大到小排序,遍历从截止日期到第一天,如果所有天都有作业要做,那么说明这个作业只能放弃,因为是按分数从大到小排序的,从前往后遍历时,前面已近做的作业肯定比现在这个作业扣的分数更多,因此这样算出来的答案是最小的。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define N 1001
int used[N];
struct pro{
int val,dl;
}x[N];
bool cmp(pro a,pro b)
{
if(a.val != b.val)
return a.val > b.val;
else return a.dl > b.dl;
}
int main()
{
int t,n,res;
scanf("%d",&t);
while(t--)
{
res = 0;
scanf("%d",&n);
memset(used,0,sizeof(used));
for(int i=1 ; i<=n ; i++)
scanf("%d",&x[i].dl);
for(int i=1 ; i<=n ; i++)
scanf("%d",&x[i].val);
sort(x+1,x+1+n,cmp);
// for(int i=1 ; i<=n ; i++)
// printf("%d %d\n",x[i].dl,x[i].val);
for(int i=1 ; i<=n ; i++)
{
int j=x[i].dl;
for( ; j>0 ; j--)
{
if(used[j]==0)
{
used[j] = 1;
break;
}
//if(j == 0)
}
if(j==0)
res += x[i].val;//("j: %d\n",j);
// printf("look: %d\n ",x[i].val);
}
// for(int i=1 ; i<=n ; i++)
// printf("%d ",used[i]);
printf("%d\n",res);
}
return 0;
}
E Task
m个任务要完成,每个任务需要xi分钟,难度为yi。同时又n台机器,每个机器有个工作时间wi和等级levi,只有 wi>=xi && levi >=yi时,这个机器才能完成这个任务,每完成一个任务可以获得(500*xi+2*yi)的money。问怎样才能做最对的任务,并且得到最多的钱。
xi占的权重比y大的多 所以把任务按x从大到小排序,先解决前面的任务得到的钱肯定比后面的多。对于怎样完成最多的任务,那么遍历任务,把机器时间大于当前任务的机器都加到一个集合里,然后找出能完成这个任务等级最小的机器,这样的策略是最优的。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#include<set>
#define ll long long
const int inf = 0x3f3f3f3f;
const int maxn = 100500;
struct test{
int w,d;
}t[maxn],m[maxn];
int v[maxn];
int cmp(test a,test b)
{
if(a.w!=b.w)
return a.w > b.w;
else return a.d > b.d;
}
int main()
{
ll res,num;
int nn,mm;
while(~scanf("%d%d",&nn,&mm))
{
num = res = 0;
memset(v,0,sizeof(v));
for(int i=0;i<nn;i++)
scanf("%d%d",&m[i].w,&m[i].d);
for(int i=0;i<mm;i++)
scanf("%d%d",&t[i].w,&t[i].d);
sort(m,m+nn,cmp);
sort(t,t+mm,cmp);
for(int i=0,j=0;i<mm;i++)
{
while(j<nn && m[j].w>=t[i].w)
{
v[m[j].d]++;
j++;
}
for(int z=t[i].d;z<=100;z++)
{
if(v[z])
{
v[z]--;
res += 500*t[i].w + 2*t[i].d;
num++;
break;
}
}
}
printf("%lld %lld\n",num,res);
}
return 0;
}
简单三分
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define eps 1e-5
int n,a1,b1,c1,t;
int a[10001],b[10001],c[10001];
double max1(double a,double b)
{
if(a > b) return a;
return b;
}
double cal(double k)
{
double res = a[0]* k * k + b[0] * k + c[0];
for(int i=1 ; i<n ; i++)
res = max1(res,a[i] * k * k + b[i] * k + c[i]);
return res;
}
double solve()
{
double l,r,mid,mmid;
l = 0; r = 1000;
mid = (l + r) / 1;
mmid = (mid + r) / 1;
for(int i=0 ; i<=100 ; i++)
{
// printf("1\n");
if(cal(mid) < cal(mmid)) r = mmid;
else l = mid;
mid = (r + l)/2;
mmid = (mid + r)/2;
}
return cal(l);
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=0 ; i<n ; i++)
scanf("%d%d%d",&a[i],&b[i],&c[i]);
printf("%.4lf\n",solve());
}
}
G http://acm.hit.edu.cn/hojx/showcontest/41/G/
二分 我不会
H http://poj.org/problem?id=3258
一条直线,已知起点和终点,中间有些点,只能走给出的点从起点走到终点,二分答案即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<deque>
#include<stack>
#include<list>
#include<map>
#include<vector>
using namespace std;
#define ll long long
const int maxn = 50500;
const int inf = 0x3f3f3f3f;
int l,n,m;
int a[maxn];
int bs(int l,int r,int k)
{
while(l<=r)
{
int sub = 0;
int cnt = 0;
int mid = (l+r) >> 1;
for(int i=1;i<=n+1;i++)
{
if(mid >= a[i]-a[sub]) cnt++;
else sub = i;
}
if(cnt > k) r = mid - 1;
else l = mid + 1;
}
return l;
}
int main()
{
while(~scanf("%d%d%d",&l,&n,&m))
{
a[0] = 0;
a[n+1] = l;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
printf("%d\n",bs(0,l,m));
}
}
不会
J http://acm.hit.edu.cn/hojx/showcontest/40/J/
不会。。。