Hdu 2015 Multi-University Training Contest2

1002

题面

Problem Description
Your current task is to make a ground plan for a residential building located in HZXJHS. So you must determine a way to split the floor building with walls to make apartments in the shape of a rectangle. Each built wall must be paralled to the building’s sides.

The floor is represented in the ground plan as a large rectangle with dimensions n×m, where each apartment is a smaller rectangle with dimensions a×b located inside. For each apartment, its dimensions can be different from each other. The number a and b must be integers.

Additionally, the apartments must completely cover the floor without one 1×1 square located on (x,y). The apartments must not intersect, but they can touch.

For this example, this is a sample of n=2,m=3,x=2,y=2.

To prevent darkness indoors, the apartments must have windows. Therefore, each apartment must share its at least one side with the edge of the rectangle representing the floor so it is possible to place a window.

Your boss XXY wants to minimize the maximum areas of all apartments, now it’s your turn to tell him the answer.

Input
There are at most 10000 testcases.
For each testcase, only 4 space-separated integers,n,m,x,y(1≤n,m≤108,n×m>1,1≤x≤n,1≤y≤m).

Output
For each testcase, print only one interger, representing the answer.

Sample Input

2 3 2 2
3 3 1 1

Sample Output

1
2

Hint

Case 1 :

You can split the floor into five 1×1 apartments. The answer is 1.

Case 2:

You can split the floor into three 2×1 apartments and two 1×1 apartments. The answer is 2.

If you want to split the floor into eight 1×1 apartments, it will be unacceptable because the apartment located on (2,2) can’t have windows.

题意

给一个n * m的矩形,然后在矩形内部的x,y点有一个坏房间。
现在要你来建房间,要求是每个房间都要与大矩形的边相邻。
求多种房间建法当中,最大房间所用的面积最小的情况,输出这个面积。
看样例就能懂了。

解析

首先,如果n > m,就直接swap(n,m),swap(x,y)。
这样,省去了之后的大小方向的判断。
然后,每个房间必然是一个 1 * k 的形状。因为如果一个房间是 t * k的,它可以拆分成t个1*k。
再然后,考虑没有坏房间的情况,就沿着n边平分就行了,此时答案是(n+1)/2。
然后将坏房间的情况考虑进来:
1.若坏房间在四个顶点,余下的点都可以满足不考虑坏房间来排:
这里写图片描述
2.若坏房间在奇数n==m的中间,显然可以减掉1:
这里写图片描述
3.若坏房间在其他位置,则应该加入判断:
首先在坏房间左右上,取小的那一半来算,因为大的那一半直接可以按照没有坏房间的情况来搞;
然后对于坏房间上下,取大的那一半来搞,因为小的那一半直接就可以满足了;
然后取左右的小和上下的大的小,最后与原来的答案比较取大就行了。
这里写图片描述

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 1e6 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    int n, m, x, y;
    while (~scanf("%d%d%d%d", &n, &m, &x, &y))
    {
        if (n > m)
        {
            swap(n, m);
            swap(x, y);
        }

        int ans = (n + 1) / 2;

        if (n == m && (n & 1) && x == y && 2 * x == n + 1)
        {
            ans--;
            printf("%d\n", ans);
            continue;
        }

        if ((x != 1 && y != 1) || (x != 1 && y != m) || (x != n && y != 1) || (x != n && y != m))
        {
            int left = y, right = m - y + 1;
            int up = x - 1, down = n - x;
            int tx = max(up, down);
            int ty = min(left, right);
            int t = min(tx, ty);
            ans = max(t, ans);
        }
        printf("%d\n", ans);
    }

    return 0;
}

1004

题面

Problem Description
There are n apple trees planted along a cyclic road, which is L metres long. Your storehouse is built at position 0 on that cyclic road.
The ith tree is planted at position xi, clockwise from position 0. There are ai delicious apple(s) on the ith tree.

You only have a basket which can contain at most K apple(s). You are to start from your storehouse, pick all the apples and carry them back to your storehouse using your basket. What is your minimum distance travelled?

1≤n,k≤105,ai≥1,a1+a2+…+an≤105
1≤L≤109
0≤x[i]≤L

There are less than 20 huge testcases, and less than 500 small testcases.

Input
First line: t, the number of testcases.
Then t testcases follow. In each testcase:
First line contains three integers, L,n,K.
Next n lines, each line contains xi,ai.

Output
Output total distance in a line for each testcase.

Sample Input

2
10 3 2
2 2
8 2
5 1
10 4 1
2 2
8 2
5 1
0 10000

Sample Output

18
26

题意

在一个圆上有很多点,给每个点距离原点的距离x,和这个点上的苹果数a。现在你有一个篮子,篮子的容量是k。求你把这些苹果全收割完,走的路程最少是多少。

解析

想贪心想了好久,写了一个nlogn的贪心,然后哇了。
网上有人用dp来做,学着写了一个。感觉非常神。
用dp[ 0 ] [ i ]来表示顺时针走的时候,取 i 个苹果所需要的最短路程;
同理 dp [ 1 ] [ i ] 来表示逆时针走的时候,取了i个苹果所需要的最短路程。
状态转移方程:
dp[ 0 ] [ now ] = dp[ 0 ] [ pre ] + dis;
其中:
pre = now - k < 0 ? 0 : now - k;
dis = min(l, 2 * appleT[i].x) – 顺时针
dis = min(l, 2 * (l - appleT[i].x)) –逆时针

然后最后的答案就是:

for (int i = 0; i <= sum; i++)
      ans = min(ans, dp[0][i] + dp[1][sum - i]);

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

struct Node
{
    LL x;
    LL a;
    bool operator < (const Node &b)const
    {
        return x < b.x;
    }
} appleT[maxn];

LL dp[2][maxn];

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
    #endif // LOCAL
    int ncase;
    scanf("%d", &ncase);
    while (ncase--)
    {
        LL n, k, l;
        scanf("%I64d%I64d%I64d", &l, &n, &k);
        LL sum = 0;
        for (int i = 0; i < n; i++)
        {
            scanf("%I64d%I64d", &appleT[i].x, &appleT[i].a);
            sum += appleT[i].a;
        }
        sort(appleT, appleT + n);

        memset(dp, 0, sizeof(dp));
        LL now = 1;
        for (int i = 0; i < n; i++)
        {
            LL dis = min(l, 2 * appleT[i].x);
            for (int j = 1; j <= appleT[i].a; j++)
            {
                LL pre = now - k < 0 ? 0 : now - k;
                dp[0][now] = dp[0][pre] + dis;
                now++;
            }
        }
        now = 1;
        for (int i = n - 1; i >= 0; i--)
        {
            LL dis = min(l, 2 * (l - appleT[i].x));
            for (int j = 1; j <= appleT[i].a; j++)
            {
                LL pre = now - k < 0 ? 0 : now - k;
                dp[1][now] = dp[1][pre] + dis;
                now++;
            }
        }
        LL ans = 1e20;
        for (int i = 0; i <= sum; i++)
        {
            ans = min(ans, dp[0][i] + dp[1][sum - i]);
        }
        printf("%I64d\n", ans);
    }
    return 0;
}

1006

题面

Problem Description
There are n people and m pairs of friends. For every pair of friends, they can choose to become online friends (communicating using online applications) or offline friends (mostly using face-to-face communication). However, everyone in these n people wants to have the same number of online and offline friends (i.e. If one person has x onine friends, he or she must have x offline friends too, but different people can have different number of online or offline friends). Please determine how many ways there are to satisfy their requirements.

Input
The first line of the input is a single integer T (T=100), indicating the number of testcases.

For each testcase, the first line contains two integers n (1≤n≤8) and m (0≤m≤n(n−1)2), indicating the number of people and the number of pairs of friends, respectively. Each of the next m lines contains two numbers x and y, which mean x and y are friends. It is guaranteed that x≠y and every friend relationship will appear at most once.

Output
For each testcase, print one number indicating the answer.

Sample Input

2
3 3
1 2
2 3
3 1
4 4
1 2
2 3
3 4
4 1

Sample Output

0
2

题意

有n(8)个人,他们之间有m个关系。
现在,每个人都有一些朋友,在关系网当中,每个人必须有相同数量的网友和现实朋友。
然后给定关系,让你来分配每个人网友和现实朋友的数量,然后问能分配成功的有多少种。

解析

开始一直考虑用状态压缩来枚举边的关系,还是太年轻。
代码1用最大深度点来剪枝,判断当前深度的边,如果到达当前深度时这个点在之后的边中还可以访问 || 当前节点的好友数平衡,则可以继续往下搜。
代码2是队友的代码。
如果一开始就听他的思路这题应该能快一点a出来吧。

代码

1:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 1e6 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int n, m;
//int stateNum[] = {0,0,2,0,6,0,20};
//int state[][30] =
//{{0}, {0}, {1, 2}, {0}, {3,5,6,9,10,12},{0},
//{7,11,13,14,19,21,22,25,26,28,35,37,38,41,42,44,49,50,52,56};

LL ans;

int num[30];
int degree[30];
int maxDep[30];

struct Edge
{
    int fr, to;
} e[30];

void dfs(int dep)
{
    if (dep >= m)
    {
        ans++;
        return;
    }
    int fr = e[dep].fr;
    int to = e[dep].to;
    num[fr] += 1;
    num[to] += 1;
    if ((num[fr] == 0 || maxDep[fr] > dep) && (num[to] == 0 || maxDep[to] > dep))
        dfs(dep + 1);
    num[fr] -= 2;
    num[to] -= 2;
    if ((num[fr] == 0 || maxDep[fr] > dep) && (num[to] == 0 || maxDep[to] > dep))
        dfs(dep + 1);
    num[fr] += 1;
    num[to] += 1;
    return;
}

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
    #endif // LOCAL
    int ncase;
    scanf("%d", &ncase);
    while (ncase--)
    {
        scanf("%d%d", &n, &m);
        memset(degree, 0, sizeof(degree));
        memset(num, 0, sizeof(num));
        for (int i = 0; i < m; i++)
        {
            int fr, to;
            scanf("%d%d", &fr, &to);
            e[i].fr = fr;
            e[i].to = to;

            degree[fr]++;
            degree[to]++;

            maxDep[fr] = i;
            maxDep[to] = i;
        }
        if (m & 1)
        {
            printf("0\n");
            continue;
        }

        bool flag = true;
        for (int i = 1; i <= n; i++)
        {
            if (degree[i] & 1)
            {
                flag = false;
                break;
            }
        }

        if (!flag)
        {
            printf("0\n");
            continue;
        }

        ans = 0;
        dfs(0);
        printf("%I64d\n", ans);
    }
    return 0;
}

2:

#include <cstdio>
#include <cstring>

int g[10][10];
int degree[10];
int sum[10];
int n,m,ans;
int dx[] = {1,-1};

void dfs(int x, int y)
{
    //writeln(x);
    if(g[x][y] == 2)
    {
        for(int i = 0; i < 2; i++)
        {
            //printf("%d %d %d\n",x, y, i);
            g[x][y] = g[y][x] = dx[i];
            sum[x] += dx[i];
            sum[y] += dx[i];
            //printf("%d %d\n",x,b[x]);
            if(y < n)
                dfs(x, y + 1);
            else if(y == n)
            {
                if(x == n)
                {
                    if(sum[x] == 0)
                    {
                        ans++;
                    }
                    //return;
                }
                else if(x < n)
                {
                    if(sum[x] == 0)
                        dfs(x + 1, 1);
                    //else return;
                }
            }
            g[x][y] = g[y][x] = 2;
            sum[x] -= dx[i];
            sum[y] -= dx[i];
        }
    }
    else
    {
        if(y < n)
            dfs(x, y + 1);
        else if(y == n)
        {
            if(x == n)
            {
                if(sum[x] == 0)
                {
                    ans++;
                }
                return;
            }
            else if(x < n)
            {
                if(sum[x] == 0)
                    dfs(x + 1, 1);
                else
                    return;
            }
        }
    }
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d %d", &n, &m);
        memset(g, 0, sizeof(g));
        memset(sum, 0, sizeof(sum));
        memset(degree, 0, sizeof(degree));
        for(int i = 1; i <= m; i++)
        {
            int x,y;
            scanf("%d %d", &x, &y);
            g[x][y] = g[y][x] = 2;
            degree[x]++;
            degree[y]++;
        }
        bool flag = true;
        for(int i = 1; i <= n; i++)
        {
            if(degree[i]%2!=0)
            {
                printf("0\n");
                flag = false;
                break;
            }
        }
        if(flag)
        {
            ans = 0;
            dfs(1,1);
            printf("%d\n",ans);
        }
    }
    return 0;
}

1009

题面

Problem Description

Recently Rikka falls in love with an old but interesting game – 24 points. She wants to become a master of this game, so she asks Yuta to give her some problems to practice.

Quickly, Rikka solved almost all of the problems but the remained one is really difficult:

In this problem, you need to write a program which can get 24 points with n numbers, which are all equal to n.

Input

There are no more then 100 testcases and there are no more then 5 testcases with n≥100. Each testcase contains only one integer n (1≤n≤105)

Output

For each testcase:

If there is not any way to get 24 points, print a single line with -1.

Otherwise, let A be an array with 2n−1 numbers and at firsrt Ai=n (1≤i≤n). You need to print n−1 lines and the ith line contains one integer a, one char b and then one integer c, where 1≤a, c < n+i and b is “+”,”-“,”*” or “/”. This line means that you let Aa and Ac do the operation b and store the answer into A(n+i).

If your answer satisfies the following rule, we think your answer is right:

  1. A(2n−1)=24
  2. Each position of the array A is used at most one tine.
  3. The absolute value of the numerator and denominator of each element in array A is no more than 109

Sample Input

4

Sample Output

1 * 2
5 + 3
6 + 4

题意

给 n 个数字 n 的矩阵 (a1, a2, a3 … an),然后用这些数,计算n-1次算24。
输出格式是要求把每次计算完了以后的值放在a数组里面,并且每个数只能用一次,比如一开始的时候a1 + a2的结果放在a(n+1)里面,然后a1与a2不能再使用。

解析

如果LGG在能话这题应该他很轻松就构造过去了。
记得有一次和他做cf的时候就是差不多的一道24点题,他想了一会就构造过去了。
首先,发现最少用每 5 个同样的数就可以凑出4,然后 6 个同样的数可以凑出 6,所以 n > 13 之后的数构造24是有规律的,只要凑出一个4和一个6,然后余下的搞成1或者0就行了。
13之前的直接用dfs暴出来了。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 1e6 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

double n;
int t;
int path[1000];// 1+ 2- 3* 4/
bool flag;

void dfs(int dep, double sum)
{
    if (flag)
        return;
    if (dep >= t - 2)
    {
        if (sum == 24.0)
        {
            flag = true;

            if (path[0] == 1)
                printf("1 + 2\n");
            if (path[0] == 2)
                printf("1 - 2\n");
            if (path[0] == 3)
                printf("1 * 2\n");
            if (path[0] == 4)
                printf("1 / 2\n");
            for (int i = 1; i <= dep; i++)
            {
                if (path[i] == 1)
                    printf("%d + %d\n", i + t, i + 2);
                if (path[i] == 2)
                    printf("%d - %d\n", i + t, i + 2);
                if (path[i] == 3)
                    printf("%d * %d\n", i + t, i + 2);
                if (path[i] == 4)
                    printf("%d / %d\n", i + t, i + 2);
//                printf("%d ", path[i]);
            }
        }
        return;
    }

    path[dep + 1] = 1;
    dfs(dep + 1, sum + n);

    path[dep + 1] = 2;
    dfs(dep + 1, sum - n);

    path[dep + 1] = 3;
    dfs(dep + 1, sum * n);

    path[dep + 1] = 4;
    dfs(dep + 1, sum / n);

}

void solve()
{
    while (~scanf("%lf", &n))
    {
        t = n;
        if (t == 1 || t == 2 || t == 3)
        {
            printf("-1\n");
            continue;
        }
        if (t <= 13)
        {
            memset(path, -1, sizeof(path));
            flag = false;

            path[0] = 1;
            dfs(0, n + n);

            path[0] = 2;
            dfs(0, n - n);

            path[0] = 3;
            dfs(0, n * n);

            path[0] = 4;
            dfs(0, n / n);
        }
        else
        {
            //a[t + 4] = 4
            printf("1 + 2\n");
            printf("%d + 3\n", t + 1);
            printf("%d + 4\n", t + 2);
            printf("%d / 5\n", t + 3);

            //a[t + 10] = 6
            printf("6 + 7\n");
            printf("%d + 8\n", t + 5);
            printf("%d + 9\n", t + 6);
            printf("%d + 10\n", t + 7);
            printf("%d + 11\n", t + 8);
            printf("%d / 12\n", t + 9);

            if (t % 2)
            {
                printf("13 - 14\n");
                for (int i = 15; i <= t; i++)
                {
                    printf("%d * %d\n", t + 11 + i - 15, i);
                }
                printf("%d + %d\n", t + 4, (t << 1) - 3);
                printf("%d * %d\n", t + 10, (t << 1) - 2);
            }
            else
            {
                printf("13 * %d\n", t + 4);
                for (int i = 14; i <= t; i++)
                {
                    if (i % 2)
                        printf("%d * %d\n", t + 11 + i - 14, i);
                    else
                        printf("%d / %d\n", t + 11 + i - 14, i);
                }
                printf("%d * %d\n", t + 10, (t << 1) - 2);

            }

        }
    }
}

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
//    while (~scanf("%lf", &n))
//    {
//        memset(path, -1, sizeof(path));
//        flag = false;
//        t = n;
//
//        path[0] = 1;
//        dfs(0, n + n);
//
//        path[0] = 2;
//        dfs(0, n - n);
//
//        path[0] = 3;
//        dfs(0, n * n);
//
//        path[0] = 4;
//        dfs(0, n / n);
//    }
    solve();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值