NUPT大二队员淘汰赛1题解

NUPT大二队员淘汰赛1


比赛链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=101409#overview      

密码:acm1248


 Problem 1920 Left Mouse Button

Accept: 380    Submit: 710
Time Limit: 1000 mSec    Memory Limit : 32768 KB

 Problem Description

Mine sweeper is a very popular small game in Windows operating system. The object of the game is to find mines, and mark them out. You mark them by clicking your right mouse button. Then you will place a little flag where you think the mine is. You click your left mouse button to claim a square as not being a mine. If this square is really a mine, it explodes, and you lose. Otherwise, there are two cases. In the first case, a little colored numbers, ranging from 1 to 8, will display on the corresponding square. The number tells you how many mines are adjacent to the square. For example, if you left-clicked a square, and a little 8 appeared, then you would know that this square is surrounded by 8 mines, all 8 of its adjacent squares are mines. In the second case, when you left-click a square whose all adjacent squares are not mines, then all its adjacent squares (8 of its adjacent squares) are mine-free. If some of these adjacent squares also come to the second case, then such deduce can go on. In fact, the computer will help you to finish such deduce process and left-click all mine-free squares in the process. The object of the game is to uncover all of the non-mine squares, without exploding any actual mines. Tom is very interesting in this game. Unfortunately his right mouse button is broken, so he could only use his left mouse button. In order to avoid damage his mouse, he would like to use the minimum number of left clicks to finish mine sweeper. Given the current situation of the mine sweeper, your task is to calculate the minimum number of left clicks.

 Input

The first line of the input contains an integer T (T <= 12), indicating the number of cases. Each case begins with a line containing an integer n (5 <= n <= 9), the size of the mine sweeper is n×n. Each of the following n lines contains n characters M ij(1 <= i,j <= n), M ij denotes the status of the square in row i and column j, where ‘@’ denotes mine, ‘0-8’ denotes the number of mines adjacent to the square, specially ‘0’ denotes there are no mines adjacent to the square. We guarantee that the situation of the mine sweeper is valid.

 Output

For each test case, print a line containing the test case number (beginning with 1) and the minimum left mouse button clicks to finish the game.

 Sample Input

1
9
001@11@10
001111110
001111110
001@22@10
0012@2110
221222011
@@11@112@
2211111@2
000000111

 Sample Output

Case 1: 24

 Source

2010年全国大学生程序设计邀请赛(福州)

题目分析:题意读懂就行了,遇到'0'就搜,访问的标记下,最后再扫一下,把没访问到的且不是雷的点算上
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n;
char mp[20][20];
int dx[8] = {0, 0, 1, 1, 1, -1, -1, -1};
int dy[8] = {1, -1, 0, 1, -1, 0, 1, -1};

void DFS(int x, int y)
{
    mp[x][y] = '#';
    for(int i = 0; i < 8; i++)
    {
        int xx = x + dx[i];
        int yy = y + dy[i];
        if(xx >= 1 && yy >= 1 && xx <= n && yy <= n && mp[xx][yy] != '#' && mp[xx][yy] != '@')
        {
            if(mp[xx][yy] == '0')
                DFS(xx, yy);
            else
                mp[xx][yy] = '#';
        }
    }
    return;
}

int main()
{
    int T;
    scanf("%d", &T);
    for(int ca = 1; ca <= T; ca++)
    {
        int ans = 0;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
            scanf("%s", mp[i] + 1);
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= n; j++)
            {
                if(mp[i][j] == '0')
                {
                    DFS(i, j);
                    ans ++;
                }
            }
        }
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                if(mp[i][j] != '#' && mp[i][j] != '@')
                    ans ++;
        printf("Case %d: %d\n", ca, ans);
    }
}


matrix

                                                                     Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
                                                                                              Total Submission(s): 588    Accepted Submission(s): 339

Problem Description
Given a matrix with  n  rows and  m  columns (  n+m  is an odd number ), at first , you begin with the number at top-left corner (1,1) and you want to go to the number at bottom-right corner (n,m). And you must go right or go down every steps. Let the numbers you go through become an array  a1,a2,...,a2k . The cost is  a1a2+a3a4+...+a2k1a2k . What is the minimum of the cost?
 
Input
Several test cases(about  5 )
For each cases, first come 2 integers,  n,m(1n1000,1m1000)
N+m is an odd number.
Then follows  n  lines with  m  numbers  ai,j(1ai100)

Output
For each cases, please output an integer in a line as the answer.
 
Sample Input
   
   
2 3 1 2 3 2 2 1 2 3 2 2 1 1 2 4
 
Sample Output
   
   
4 8
 
Source
 
题目大意:就是左上到右下求那个公式的最大值
题目分析:当前状态由前两个的决定,且必须是行加列为奇数的点,一共四种情况,一条竖线上,一条横线上,还有|_和一|这两种,dp一下即可
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
int const MAX = 1e3 + 5;
ll dp[MAX][MAX], a[MAX][MAX];

int main()
{
    int n, m;
    while(scanf("%d %d", &n, &m) != EOF)
    {
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                scanf("%I64d", &a[i][j]);
        memset(dp, 0, sizeof(dp));
        dp[1][2] = a[1][2] * a[1][1];
        dp[2][1] = a[2][1] * a[1][1];
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= m; j++)
            {
                if((i + j) & 1)
                {
                    if(j > 2 && dp[i][j - 2])
                    {
                        if(dp[i][j])
                            dp[i][j] = min(dp[i][j], dp[i][j - 2] + a[i][j] * a[i][j - 1]);
                        else
                            dp[i][j] = dp[i][j - 2] + a[i][j] * a[i][j - 1];
                    }
                    if(i > 2 && dp[i - 2][j])
                    {
                        if(dp[i][j])
                            dp[i][j] = min(dp[i][j], dp[i - 2][j] + a[i][j] * a[i - 1][j]);
                        else
                            dp[i][j] = dp[i - 2][j] + a[i][j] * a[i - 1][j];
                    }
                    if(i > 1 && j > 1 && dp[i - 1][j - 1])
                    {
                        if(dp[i][j])
                            dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + min(a[i][j - 1] * a[i][j], a[i - 1][j] * a[i][j]));
                        else
                            dp[i][j] = dp[i - 1][j - 1] + min(a[i][j - 1] * a[i][j], a[i - 1][j] * a[i][j]);
                    }    
                }
            }
        }
        printf("%I64d\n", dp[n][m]);
    }
}


 Problem 2171 防守阵地 II

Accept: 296    Submit: 1115
Time Limit: 3000 mSec    Memory Limit : 32768 KB

 Problem Description

部队中总共有N个士兵,每个士兵有各自的能力指数Xi,在一次演练中,指挥部确定了M个需要防守的地点,指挥部将选择M个士兵依次进入指定地点进行防守任务,获得的参考指数即为M个士兵的能力之和。随着时间的推移,指挥部将下达Q个指令来替换M个进行防守的士兵们,每个参加完防守任务的士兵由于疲惫等原因能力指数将下降1。现在士兵们排成一排,请你计算出每次进行防守的士兵的参考指数。

 Input

输入包含多组数据。

输入第一行有两个整数N,M,Q(1<=N<=100000,1<=M<=1000,1<=Q<=100000),第二行N个整数表示每个士兵对应的能力指数Xi(1<=Xi<=1000)。

接下来Q行,每行一个整数X,表示在原始队列中以X为起始的M个士兵替换之前的士兵进行防守。(1<=X<=N-M+1)

对于30%的数据1<=M,N,Q<=1000。

 Output

输出Q行,每行一个整数,为每次指令执行之后进行防守的士兵参考指数。

 Sample Input

5 3 3
2 1 3 1 4
1
2
3

 Sample Output

6
3
5

题目分析:士兵的能力可以减为负,所以直接线段树区间更新就行了,查询完区间每个值直接减1,模板题,当然树状数组也可搞
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
using namespace std;
int const MAX = 1e5 + 5;
int sum[MAX << 2], lazy[MAX << 2];
int n, m, q;

void PushUp(int rt)
{
    sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}

void PushDown(int ln, int rn, int rt)
{
    if(lazy[rt])
    {
        sum[rt << 1] -= lazy[rt] * ln;
        sum[rt << 1 | 1] -= lazy[rt] * rn;
        lazy[rt << 1] += lazy[rt];
        lazy[rt << 1 | 1] += lazy[rt];
        lazy[rt] = 0;
    }
}

void Build(int l, int r, int rt)
{
    lazy[rt] = 0;
    if(l == r)
    {
        scanf("%d", &sum[rt]);
        return;
    }
    int mid = (l + r) >> 1;
    Build(lson);
    Build(rson);
    PushUp(rt);
}

void Update(int L, int R, int c, int l, int r, int rt)
{
    if(L <= l && r <= R)
    {
        lazy[rt] += 1;
        sum[rt] +=  -(r - l + 1);
        return;
    }
    int mid = (l + r) >> 1;
    PushDown(mid - l + 1, r - mid, rt);
    if(L <= mid)
        Update(L, R, c, lson);
    if(mid < R)
        Update(L, R, c, rson);
    PushUp(rt);
}

int Query(int L, int R, int l, int r, int rt)
{
    if(L <= l && r <= R)
        return sum[rt];
    int mid = (l + r) >> 1, ans = 0;
    PushDown(mid - l + 1, r - mid, rt);
    if(L <= mid)
        ans += Query(L, R, lson);
    if(mid < R)
        ans += Query(L, R, rson);
    return ans;
}

int main()
{
    while(scanf("%d %d %d", &n, &m, &q) != EOF)
    {
        Build(1, n, 1);
        while(q --)
        {
            int x;
            scanf("%d", &x);
            printf("%d\n", Query(x, x + m - 1, 1, n, 1));
            Update(x, x + m - 1, -1, 1, n, 1);
        }
    }
}


Test for Job
Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 10135 Accepted: 2347

Description

Mr.Dog was fired by his company. In order to support his family, he must find a new job as soon as possible. Nowadays, It's hard to have a job, since there are swelling numbers of the unemployed. So some companies often use hard tests for their recruitment.

The test is like this: starting from a source-city, you may pass through some directed roads to reach another city. Each time you reach a city, you can earn some profit or pay some fee, Let this process continue until you reach a target-city. The boss will compute the expense you spent for your trip and the profit you have just obtained. Finally, he will decide whether you can be hired.

In order to get the job, Mr.Dog managed to obtain the knowledge of the net profit Vi of all cities he may reach (a negative Vi indicates that money is spent rather than gained) and the connection between cities. A city with no roads leading to it is a source-city and a city with no roads leading to other cities is a target-city. The mission of Mr.Dog is to start from a source-city and choose a route leading to a target-city through which he can get the maximum profit.

Input

The input file includes several test cases. 
The first line of each test case contains 2 integers n and m(1 ≤ n ≤ 100000, 0 ≤ m ≤ 1000000) indicating the number of cities and roads. 
The next n lines each contain a single integer. The ith line describes the net profit of the city iVi (0 ≤ |Vi| ≤ 20000) 
The next m lines each contain two integers xy indicating that there is a road leads from city x to city y. It is guaranteed that each road appears exactly once, and there is no way to return to a previous city. 

Output

The output file contains one line for each test cases, in which contains an integer indicating the maximum profit Dog is able to obtain (or the minimum expenditure to spend)

Sample Input

6 5
1
2
2
3
3
4
1 2
1 3
2 4
3 4
5 6

Sample Output

7

Hint


题目大意: 给多棵树,求从根到叶子的最大值
题目分析:本题暴搜会超时,必须用记忆化搜索做,而且不是一颗树,先用ind数组统计根的个数及入度,然后从每个根出发记忆化搜索整棵树得到一个最大值,注意这里的边权可能为负
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
int const MAX = 1e5 + 5;
int const INF = 2147483640;
int n, m;
int dp[MAX], val[MAX], ind[MAX];
vector <int> vt[MAX];

int DFS(int x)
{
    if(dp[x])
        return dp[x];
    int sz = vt[x].size();
    if(sz == 0)
        return val[x];
    int tmp = -INF;
    for(int i = 0; i < sz; i++)
    {
        int u = vt[x][i];
        tmp = max(tmp, val[x] + DFS(u));
    }
    return dp[x] = tmp;
}

int main()
{
    while(scanf("%d %d", &n, &m) != EOF)
    {
        for(int i = 1; i <= n; i++)
            vt[i].clear();
        memset(ind, 0, sizeof(ind));
        memset(dp, 0, sizeof(dp));
        for(int i = 1; i <= n; i++)
            scanf("%d", &val[i]);
        for(int i = 0; i < m; i++)
        {
            int u, v;
            scanf("%d %d", &u, &v);
            vt[u].push_back(v);
            ind[v]++;
        }
        int ans = -INF;
        for(int i = 1; i <= n; i++)
            if(!ind[i])
                ans = max(ans, DFS(i));
        printf("%d\n", ans);
    }
}


C. Terse princess
time limit per test
1 second
memory limit per test
256 megabytes

«Next please», — the princess called and cast an estimating glance at the next groom.The princess intends to choose the most worthy groom, this is, the richest one. Whenever she sees a groom who is more rich than each of the previous ones, she says a measured «Oh...». Whenever the groom is richer than all previous ones added together, she exclaims «Wow!» (no «Oh...» in this case). At the sight of the first groom the princess stays calm and says nothing.

The fortune of each groom is described with an integer between 1 and 50000. You know that during the day the princess saw n grooms, said «Oh...» exactly a times and exclaimed «Wow!» exactly b times. Your task is to output a sequence of n integers t1, t2, ..., tn, where tidescribes the fortune of i-th groom. If several sequences are possible, output any of them. If no sequence exists that would satisfy all the requirements, output a single number -1.

Input

The only line of input data contains three integer numbers n, a and b (1 ≤ n ≤ 100, 0 ≤ a, b ≤ 15, n > a + b), separated with single spaces.

Output

Output any sequence of integers t1, t2, ..., tn, where ti (1 ≤ ti ≤ 50000) is the fortune of i-th groom, that satisfies the given constraints. If no sequence exists that would satisfy all the requirements, output a single number -1.

Sample test(s)
input
10 2 3
output
5 1 3 6 16 35 46 4 200 99
input
5 0 0
output
10 10 6 6 5
Note

Let's have a closer look at the answer for the first sample test.

  • The princess said «Oh...» (highlighted in bold): 5 1 3 6 16 35 46 4 200 99.
  • The princess exclaimed «Wow!» (highlighted in bold): 5 1 3 6 16 35 46 4 200 99.

题目大意:构造一个n个数的序列,满足公主叫了a次Oh和b次Wow,公主遇到一个数字,这个数字比前面的所有数字都大时她会叫Oh,公主遇到一个数字,这个数字比前面所有数字的和都大时,公主会叫Wow,叫Wow的话就不叫Oh了,构造的数字不能大于5万,如果不存在则输出-1

题目分析:先明确一点,前两个数字,如果第二个比第一个大,这种情况公主会叫Wow,这题构造方法不唯一,最简单的应该是二进制法,举个例子比如b等于3这时候我们就可以构造0001,0010,0100,1000,0001+0010 = 0011正好比0100小1,同理0001+0010+0100 = 0111,正好比1000小1,又b最大为15,所以构造b的值最大到2^15=32768,然后构造a就方便了,直接往后依次加1即可,构造完a,b,剩下来的数全都等于构造a时的最后一个数即可

#include <cstdio>
int ans[105];

int main()
{
    int a, b, n, cur = 1;
    scanf("%d %d %d", &n, &a, &b);
    ans[1] = 1;
    for(int i = 2; i <= n; i++)
    {
        if(b)
        {
            ans[i] = 1 << (i - 1);
            b --;
        }
        else if(a && i > 2)
        {
            ans[i] = ans[i - 1] + 1;
            a --;
        }
        else
            ans[i] = ans[i - 1];   
    }
    if(a || b)
        printf("-1\n");
    else 
    {
        for(int i = 1; i < n; i++)
            printf("%d ",ans[i]);
        printf("%d\n", ans[n]);
    }
}


1256: 天朝的单行道

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 277   Solved: 90
[ Submit][ Status][ Web Board]

Description

    在另一个平行宇宙中,有一个神奇的国度名叫天朝。天朝一共有N个城市(标号分别为1, 2, …, N),M条道路,为了方便交通管制,天朝的M条道路都是单行道。
    不久前天朝大选,小Q当选了天朝的总统。小Q家住在城市1,但天朝的办公地点在城市N,于是为了便于工作,小Q决定举家从城市1搬迁到城市N去居住。然而小Q惊奇的发现,现在并不存在从城市1出发到城市N路线。
    但这点难题是无法阻挡天朝总统的,小Q决定行使总统的权利下令更改一些道路的通行方向,使得至少存在一条从城市1出发到城市N的路线,但为了节省时间和资源,他希望更改通行方向的道路尽可能少,你能帮帮小Q吗?

Input

    输入包含多组测试数据。
    对于每组测试数据,第一行包含两个正整数N (2<=N<=5000)、M (1<=M<=10000),表示天朝一共有N个城市、M条道路。接下来M行每行有两个正整数u、v (1<=u, v<=N),表示城市u和城市v之间有一条通行方向为u->v的单行道。两个城市之间可能有多条道路。

Output

    对于每组测试数据,用一行输出一个整数表示最少需要更改多少条单行道的通行方向,才能使得至少存在一条路线能够让小Q从城市1出发到城市N。
    如果没办法使得至少存在一条路线让小Q从城市1出发到城市N,则输出“-1”(不包括引号)。

Sample Input

2 1
1 2

2 1
2 1

2 0

Sample Output

0
1
-1

Source


题目分析:原来的路权值为0,然后建一条反向边权值为1,相当于如果这条反向边在你的最短路上,那就表示这条边要建,然后从1-n用SPFA跑一个最短路,dist[n]就是答案,本题用二维数组存貌似会炸

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
int const MAX = 5005;
int const INF = 1 << 30;
int n, m, dis[MAX];
bool vis[MAX];

struct EGDE  
{  
    int u, v, w;  
}e[MAX << 1];  
  
struct NODE  
{  
    int v, w;  
    NODE(int vv, int ww)  
    {  
        v = vv;  
        w = ww;  
    }  
};

vector <NODE> vt[MAX];

void SPFA(int v0)
{
    queue <int> q;
    for(int i = 1; i <= n; i++)
        dis[i] = INF;
    memset(vis, false, sizeof(vis));
    dis[v0] = 0;
    vis[v0] = true;
    q.push(v0);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = false;
        int sz = vt[u].size();
        for(int i = 0; i < sz; i++)
        {
            int v = vt[u][i].v;
            int w = vt[u][i].w;
            if(dis[v] > dis[u] + w)
            {
                dis[v] = dis[u] + w;
                if(!vis[v])
                {
                    vis[v] = true;
                    q.push(v);
                }
            }
        }
    }
    return;
}

int main()
{
    while(scanf("%d %d", &n, &m) != EOF)
    {
        for(int i = 0; i <= n; i++)
            vt[i].clear();
        for(int i = 0; i < m; i++)
            scanf("%d %d", &e[i].u, &e[i].v);
        for(int i = 0; i < m; i++)
        {
            vt[e[i].u].push_back(NODE(e[i].v, 0));
            vt[e[i].v].push_back(NODE(e[i].u, 1));
        }
        SPFA(1);
        if(dis[n] == INF)
            printf("-1\n");
        else
            printf("%d\n", dis[n]);
    }   
}


How many integers can you find

                                                                Time Limit: 12000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
                                                                                     Total Submission(s): 6047    Accepted Submission(s): 1734

Problem Description
  Now you get a number N, and a M-integers set, you should find out how many integers which are small than N, that they can divided exactly by any integers in the set. For example, N=12, and M-integer set is {2,3}, so there is another set {2,3,4,6,8,9,10}, all the integers of the set can be divided exactly by 2 or 3. As a result, you just output the number 7.
 
Input
  There are a lot of cases. For each case, the first line contains two integers N and M. The follow line contains the M integers, and all of them are different from each other. 0<N<2^31,0<M<=10, and the M integer are non-negative and won’t exceed 20.
 
Output
  For each case, output the number.
 
Sample Input
  
  
12 2 2 3
 
Sample Output
  
  
7
 
Source
 

题目大意:给一个数n和一个含有m个数的集合,求[1, n-1]中可以被集合中任意一个数整除的数集大小

题目分析:很基础的容斥题,有个坑点,集合中可能有0,如果有0的话,直接把0去掉,还可以加个小特判,如果有1的话直接输出n就行了,注意这里容斥不是把数字直接相乘,因为它们不一定互质,所以算的是数字间的最小公倍数,举个简单例子:

25 2
6 8
答案如果直接用24 / 6 + 24 / 8 - 24 / (6 * 8)得到的是7,显然答案是6,因为24没有被容斥掉,所以我们要拿两个数的最小公倍数去容斥

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
int a[25], b[25];
ll ans;
int n, m, cnt;

ll gcd(ll a, ll b)
{
    return b ? gcd(b, a % b) : a;  
}

ll lcm(int a, int b)
{
    return (ll) a * b / gcd(a, b);
}

void DFS(int idx, ll cur, int sgin)
{
    for(int i = idx; i < cnt; i++)
    {
        ll tmp = lcm(cur, (ll)b[i]);
        ans += (ll) sgin * (n / tmp);
        DFS(i + 1, tmp, -sgin);
    }
}

int main()
{
    while(scanf("%d %d", &n, &m) != EOF)
    {
        n --;
        cnt = 0;
        bool flag = false;
        for(int i = 0; i < m; i++)
        {
            scanf("%d", &a[i]);
            if(a[i] != 0)
                b[cnt ++] = a[i];
            if(a[i] == 1)
                flag = true;
        }
        if(flag)
        {
            printf("%d\n", n);
            continue;
        }
        sort(b, b + cnt);
        ans = 0;
        DFS(0, 1, 1);
        printf("%I64d\n", ans);
    }
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值