2016计蒜之道 4,5场部分题解

在每年的淘宝“双十一”时,访问量都会暴涨,服务器的请求会被流量分配程序按照一定策 略,分发给不同的进程去处理。有一类请求,有两个进程可以接受分发的请求,其中一个进程所在服务器的配置、网络传输性能等都要优于另一个进程。流量分发程 序可以知道队列中每个任务的预计处理时间,每次都会尽可能将队列中预计处理时间更多的任务分配给性能更优的进程。

假设队列当前一共有 nnn 个任务待分配,第 iii 个任务的预计处理时间为 ai(1≤i≤n)a_i(1 \leq i \leq n)ai​​(1in)。由于服务存在冷启动问题,越靠后的进程,预计处理时间越短。而队列中的 最后一个任务 因为比较特殊,预计处理时间和之前的任务 无关。即前 n−1n-1n1 个任务的预计处理时间满足 a1>a2>...>an−1a_1 > a_2 > ... > a_{n-1}a1​​>a2​​>...>an1​​。现在要从中选出一个任务列表,不能有任何两个任务在原队列中相邻。计算选出的任务队列预计处理时间之和的最大值。

输入格式

输入第一行有一个整数 n(1≤n≤104)n(1 \leq n \leq 10^{4})n(1n104​​),表示任务总数。

输入第二行有 nnn 个整数 ai(0≤ai≤104)a_i(0 \leq a_i \leq 10^{4})ai​​(0ai​​104​​),表示每个任务的预计处理时间。

输出格式

输出一个整数,表示选出的任务的预计处理时间之和的最大值。

样例输入1

5
4 3 2 1 5

样例输出1

11

样例输入2

4
5 3 1 9

样例输出2

14

提示信息

对于第一组样例,选出的总预计处理时间最大为 4+2+5=11

对于第二组样例,选出的总预计处理时间最大为 5+9=14

解法:DP求解最大子段和 ,且每个元素不能连续.选与不选第i个元素。dp[i]表示前i个元素最大和.

dp[2] = max(a[0],a[1])

dp[i] = max(dp[i-1],dp[k]+a[i])。1=<k<i-1,i>=3

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<math.h>
#include<queue>
#include<iostream>
using namespace std;
const int N = 10005;
int n;
int a[N],dp[N];
int main()
{
    while(scanf("%d",&n)!=EOF){
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            dp[i] = a[i];
        }
        dp[2] = max(a[1],a[2]);
        for(int i=3;i<=n;i++){
            for(int j=1;j<=i-2;j++){
                dp[i] = max(dp[i-1],dp[j]+a[i]);
            }
        }
        printf("%d\n",dp[n]);
    }
    return 0;
}

 

第四场B题错误的解法也过了最简单的测试。。就不贴啦。。

腾讯开发了一款益智游戏:一笔画。在一个正 nnn 边形上,将 nnn 条边的中点连结,形成一个新的正 nnn 边形,之后再在新的正 nnn 边形内连结各个中点,如此重复 kkk 次,作为游戏的初始图案。

玩家要从初始图案最外层 nnn 个顶点中的一个出发,进行无公共 端点 的一笔画。

端点 包含:

  1. 起点

  2. 终点

  3. 一笔画中方向发生改变的顶点。

画出的长度即为最后的得分,求玩家在给定的图形上最多能得多少分。

比如在一个边长为 100100100、k=1k=1k=1 的正方形图案上进行一笔画,最优的方案如下:

输入格式

输入第一行有 222 个用一个空格分隔的整数 n(3≤n≤100)n(3 \leq n \leq 100)n(3n100) 和 k(0≤k≤20)k(0 \leq k \leq 20)k(0k20),nnn 为边数,kkk 为重复次数。

输入第二行有一个浮点数 L(0<L≤103)L(0 < L \leq 10^3)L(0<L103​​),表示最外层正 nnn 边形的边长。

输出格式

输出一行,表示最多能得多少分。结果误差在 10−310^{-3}103​​ 以内均被认为是正确的。

样例输入1

4 0
100

样例输出1

300

样例输入2

4 1
100

样例输出2

562.1320343
 推一下就知道了,前面K-1(K>=1)个多边形的周长减掉一条边的一半加上最后多边形的周长减掉一条边。每个多边形周长利用余弦定理迭代求。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<math.h>
#include<queue>
#include<iostream>
using namespace std;
typedef long long LL;
int n,k;
double m;
double pi = atan(1)*4;
double l[25];
int main()
{
    while(scanf("%d%d",&n,&k)!=EOF){
        scanf("%lf",&m);
        double angle = (180*(n-2))/n;
        angle = angle*pi/180;
        l[0] = m;
        for(int i=1;i<=k;i++){
            double d = l[i-1]/2;
            l[i] = sqrt(2*d*d-cos(angle)*d*d*2);
        }

        double L=0;
        for(int i=0;i<=k;i++){
            L=L+(n-0.5)*l[i];
        }
        printf("%.7lf\n",L-l[k]/2);
    }
    return 0;
}
 
i​​,q100000;∑imi≤100000\sum_{i}m_i \leq 100000i​​mi​​100000。

样例输入

2
5 2 5 1 5 6
4 5 6 7 8
3
1 3 2 2
1 4 2 0
1 0 2 5

样例输出

4
5
5

提示信息

第一次换防后,第一支护卫队变为 5,6,5,6,第二支护卫队变为 2,5,1,7,8。若先攻击第一队再攻击第二队,需要 555 点防御力。若先攻击第二队再攻击第一队,则只需要 444 点防御力。

第二次换防后,第一支护卫队没有恶魔了,第二支护卫队变为 5,6,5,6,2,5,1,7,8

 

前两问的解法。。。是每次预算出打败每支护卫队最少需要护盾,然后排序,能够打过则将护卫的数量加到护盾上,二分枚举答案。当然第一问可以全排列暴力。。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 1005;
const int MAX = 100005;
int monster[N][N];
int temp[1000005],temp1[1000005];
int num[N],n;
int minn;
bool vis[N];
struct Node
{
    int v,id;
} ans[N];
bool can(int k)
{
    for(int i=1; i<=n; i++)
    {
        if(k>=ans[i].v) k+=num[ans[i].id];
        else return 0;
    }
    return 1;
}
bool cmp(Node a,Node b)
{
    return a.v<b.v;
}
int main()
{
    int q;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&num[i]);
            for(int j=1; j<=num[i]; j++)
            {
                scanf("%d",&monster[i][j]);
            }
        }
        scanf("%d",&q);
        while(q--)
        {
            int x,a,y,b;
            minn=999999999;
            scanf("%d%d%d%d",&x,&a,&y,&b);
            for(int i=1; i<=b; i++)
                temp[i]=monster[y][i];
            for(int i=a+1; i<=num[x]; i++)
                temp[b+i-a]=monster[x][i];
            for(int i=1; i<=a; i++)
                temp1[i]=monster[x][i];
            for(int i=b+1; i<=num[y]; i++)
                temp1[a+i-b]=monster[y][i];
            num[x]=num[x]+b-a;
            num[y]=num[y]+a-b;
            for(int i=1; i<=num[x]; i++)
            {
                monster[x][i]=temp[i];
            }
            for(int i=1; i<=num[y]; i++)
            {
                monster[y][i]=temp1[i];
            }
              for(int i=1; i<=n; i++)
            {
                int maxn=-1;
                for(int j=1; j<=num[i]; j++)
                    maxn=max(maxn,monster[i][j]-j+1);
                ans[i].v=maxn;
                ans[i].id=i;
            }
            sort(ans+1,ans+1+n,cmp);
            int l = 0,r = 100000;
            while(l<=r)
            {
                int mid = (l+r)>>1;
                if(can(mid))
                {
                    r = mid-1;
                }
                else l = mid+1;
            }
            printf("%d\n",l);
        }
    }
    return 0;
}

 

posted @ 2016-06-12 00:32  樱花庄的龙之介大人  阅读(594)  评论(0编辑  收藏  举报