HIT集训第一天

Joysticks

两个手柄只有一个充电器,不充电的手柄每分钟掉两格电,充电的手柄每分钟加一格电,一开始有一个手柄的电量是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;
}



 B Polycarp at the Radio

一个人喜欢的乐队是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]);
 } 

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);
		}
	}
}

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;
}





Error Curves

简单三分

#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());
    }
}

http://acm.hit.edu.cn/hojx/showcontest/41/G/

二分 我不会


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));
   }
}


http://poj.org/problem?id=3579


不会



http://acm.hit.edu.cn/hojx/showcontest/40/J/


不会。。。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值