2017北京林业大学「计蒜客杯」程序设计竞赛部分题解

偶数加成记

 时间限制: 2000ms  内存限制: 256M

描述

xyb这里有n个整数。xyb想要得到这n个整数最大的偶数和(即该和为偶数),每个整数最多只能加一次。请你计算出最大的这个值。

输入

输入包含多组。输入的第一个数为一个n1<=n<=100000)。下一行包括xybn个整数,以空格隔开。每个整数的范围为1~10^9

输出

请输出最大的偶数和。

样例输入复制

3

1 2 3

样例输出1

6

样例输入复制

5

999999999 999999999 999999999 999999999999999999

样例输出2

3999999996

解题思路:

偶数全部加起来,看奇数多少个,如果是奇数个那么把最小的那个剔除,如果偶数个则全部相加。

AC代码:

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <set>
#include <deque>
#include <functional>
#define maxn 100100
#define INF 0x3f3f3f3f
#define N 1010
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
ll a[maxn];
int main()
{
   int n;
   while (~scanf("%d", &n))
   {
      ll sum = 0;
      int cnt = 0;
      for (int i = 1; i <=n; i++)
      {
          ll x;
          scanf("%lld", &x);
          if (x & 1)
             a[cnt++]= x;
          else sum += x;
      }
      sort(a, a + cnt, greater<ll>());
      if (cnt & 1)
      {
          for (int i = 0; i <cnt - 1; i++)
             sum +=a[i];
      }
      else
      {
          for (int i = 0; i <cnt; i++)
             sum +=a[i];
      }
      printf("%lld\n", sum);
   }
   return 0;
}


理智逃税

时间限制: 2000ms  内存限制: 256M

描述

xyb在一个高大上的国家工作,这个国家有一个特殊的税收政策。若xyb每年的收入为n元(n>=2),那么xyb所要交的税为n的所有约数中的最大值(不包括n本身。)比如,如果xyb一年收入为6元,那么他就需要交税3元;如果xyb一年收入为25元,那么他就需要交税5元;如果xyb一年收入为2元,那么他就需要交税1元。

然而xyb是个机(jiao)智(hua)的人,他想要上交的税越少越好。所以,他决定,将每年的收入n元,拆分一下:n1+n2+...+nk=n(这里的k表示拆分的份数,k=1也是可以的),然后再将每份所要交的税一起上交即可。当然,对于每份的钱数来说,不能少于2元(如果某一份少于2元他就会被正直的人给揭发了!)

xyb想知道他最少只需要交多少钱的税,你快来帮帮他吧!

输入

输入第一行包含一个整数n2<=n<=2*10^9),表示xyb的总钱数。

输出

输出一个整数,表示xyb最少需要交多少税。

样例输入复制

4

样例输出1

2

样例输入复制

27

样例输出2

3

解题思路:

       基于哥德巴赫猜想。“对于偶数:一个大于2的偶数可以分为两个质数的和;对于奇数:一个奇数n且不为质数,若其n-2为质数,那么n可以分为两个质数的和,若n-2不为质数,那么n可以分为三个质数的和。”

AC代码:

#include<cstdio>
#include<iostream>
using namespace std;
bool isprime(int n)
{
   for (int i = 2; i*i<=n; i++)
      if (n%i == 0)
          return false;
   return true;
}
int main()
{
   int n;
   while (cin >> n)
   {
      if (isprime(n))
      {
          printf("1\n");
          continue;
      }
      if (n % 2 == 0 || isprime(n - 2))
      {
          printf("2\n");
          continue;
      }
      printf("3\n");
   }
   return 0;
}


我要吃粽子

时间限制: 1000ms  内存限制: 128M

描述

快看!高空中漂浮着好多粽子,而且越高的粽子越大!

好神奇,我要吃到最大的粽子!

地上零零散散放着K种砖块(这些砖块能帮我们吃到高处的粽子)。对于第i类砖块的描述:

1. i类砖块,每块高度皆为H

2. i类砖块共有Q个。

3. i类砖块,凡是放到高于L的高空会自动消失。

用这些砖块一块块堆砌,以此爬向天空。为了使吃到的粽子尽可能大,问我最高能爬到多高的高空?

输入

有多组数据
每组输入,第一行为一个整数K(1 <= K <= 400)
第二行为k+1行,每行三个空格分隔的整数H(1 <= H <= 100)L (1 <= L <= 40000)Q(1 <= Q<= 10),表示第i种砖块的HLQ

输出

每组输出一个整数h,表示能吃到的最大粽子所在高度。

样例输入复制

3

7 40 3

5 23 8

2 52 6

样例输出1

48

解题思路:

考虑多重背包,不同的是:每次放一个砖要考虑下面又没有东西,不能放在空中

所以先要根据最高度,排序。然后用多重背包递推求解。递推公式:

dp[i][j]=dp[i][j-h[i]] 和 used[i][j]=used[i][j-h[i]]+1 (其中i表示第i种砖块,j表示高度转移,再用used记录一下第i种砖块用的个数)

AC代码:

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define maxn 40010
#define lson root << 1
#define rson root << 1 | 1
#define lent (t[root].r -t[root].l + 1)
#define lenl (t[lson].r - t[lson].l + 1)
#define lenr (t[rson].r - t[rson].l + 1)
#define N 404
#define eps 1e-6
#define pi acos(-1.0)
#define e exp(1.0)
using namespace std;
const int mod = 1e9 + 7;
typedef long long ll;
typedef unsigned long longull;
int dp[maxn], used[maxn];
struct node
{
   int h, l, q;
   friend bool operator< (node a,node b)
   {
      return a.l < b.l;
   }
} p[N];
int main()
{
#ifndef ONLINE_JUDGE
   freopen("in.txt","r", stdin);
   freopen("out.txt","w", stdout);
   long _begin_time = clock();
#endif
   int k;
   while (~scanf("%d", &k))
   {
      for (int i = 0; i <k; i++)
          scanf("%d%d%d", &p[i].h, &p[i].l, &p[i].q);
      sort(p, p + k);
      memset(dp, 0, sizeof(dp));
      dp[0] = 1;
      for (int i = 0; i <k; i++)
      {
          memset(used, 0,sizeof(used));
          for (int j = p[i].h; j <= p[i].l; j++)
          {
             if (used[j - p[i].h] < p[i].q)
             {
                if (!dp[j]&& dp[j - p[i].h])
                {
                   dp[j]= dp[j - p[i].h];
                   used[j]= used[j - p[i].h] + 1;
                }
             }
          }
      }
      int ans = 0;
      for (int i =maxn; i >= 0;i--)
          if (dp[i])
          {
             ans =i;
             break;
          }
      printf("%d\n", ans);
   }
#ifndef ONLINE_JUDGE
   long _end_time = clock();
   printf("time =%ld ms.", _end_time -_begin_time);
#endif
   return 0;
}


Universe7去约会

时间限制: 1000ms  内存限制: 128M

描述

Universe7有个非常漂亮的女朋友,他每天都要和她去约会(嫌虐狗?上周末干啥去了!)。他的女友为了考验他,每次都选一个非常神奇的迷宫等他。在迷宫里有许多只蜗牛,如果踩到了蜗牛就会暴毙而亡。但蜗牛会在隔一定的时间消失一秒。其余的时间蜗牛就会待在那里等待大傻子去踩。

下面给出迷宫的地图图例。'.'代表可以走的路,'#'代表蜗牛,'U'代表Universe7的位置,'G'代表他女朋友的位置。每一秒钟,Universe7都可以向上向下向左向右移动一格。

输入

第一行给出样例的总数T(0<T<20),接下来有T个样例。每个样例给出迷宫的行数r列数c和蜗牛消失的间隔时间k(1<=r,c<=100,2<=k<=10)。接下来的r行代表迷宫的地图。

输出

如果Universe7可以成功约会,输出最短时间,否则输出"Please give me another chance!".

样例输入复制

2

6 6 2

...U..

...#..

.#....

...#..

...#..

..#G#.

4 4 2

U###

####

####

###G

样例输出1

7

Please give me another chance!

解题思路:

       带时间状态的广搜,考虑开三层vis[x][y][z]其中前两层表示坐标,第三层表示时间状态,当t%k==0则表示可进状态。

AC代码:

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define maxn 100010
#define lson root << 1
#define rson root << 1 | 1
#define lent (t[root].r -t[root].l + 1)
#define lenl (t[lson].r - t[lson].l + 1)
#define lenr (t[rson].r - t[rson].l + 1)
#define N 1111
#define eps 1e-6
#define pi acos(-1.0)
#define e exp(1.0)
using namespace std;
const int mod = 1e9 + 7;
typedef long long ll;
typedef unsigned long longull;
char mp[110][110];
bool vis[110][110][11];
int dir[4][2] = { { 1, 0 },{ -1, 0 },{ 0, -1 },{0, 1 } };
int r, c, k, ans;
struct node
{
   int x, y, t;
   node(int a, int b, int c) { x =a; y = b; t = c; }
};
void bfs(int stax,int stay)
{
   memset(vis, 0, sizeof(vis));
   queue<node> q;
   q.push(node(stax,stay, 0));
   vis[stax][stay][0] = 1;
   while (!q.empty())
   {
      node cur = q.front();
      q.pop();
      if (mp[cur.x][cur.y] =='G')
      {
          ans = cur.t;
          return;
      }
      for (int i = 0; i <4; i++)
      {
          int dx = cur.x + dir[i][0];
          int dy = cur.y + dir[i][1];
          int time = cur.t + 1;
          if (dx >= 0&& dx < r && dy >= 0 && dy < c &&(mp[dx][dy] !='#' || time % k == 0) &&!vis[dx][dy][time % k])
          {
             vis[dx][dy][time% k] = 1;
             q.push(node(dx, dy, time));
          }
      }
   }
}
int main()
{
#ifndef ONLINE_JUDGE
   freopen("in.txt","r", stdin);
   freopen("out.txt","w", stdout);
   long _begin_time = clock();
#endif
   int t;
   scanf("%d", &t);
   while (t--)
   {
      scanf("%d%d%d", &r,&c, &k);
      int stax, stay;
      bool flag = 0;
      for (int i = 0; i <r; i++)
      {
          scanf("%s", mp[i]);
          for (int j = 0; j < c&& !flag; j++)
             if (mp[i][j] == 'U')
             {
                stax= i;
                stay= j;
                flag= 1;
                break;
             }
      }
      ans = INF;
      bfs(stax, stay);
      if (ans < INF)
          printf("%d\n", ans);
      else
          puts("Pleasegive me another chance!");
   }
#ifndef ONLINE_JUDGE
   long _end_time = clock();
   printf("time =%ld ms.", _end_time -_begin_time);
#endif
   return 0;
}


读书好多读书读好书

时间限制: 2000ms  内存限制: 256M

描述

xyb刚度过一段繁忙的时期,终于有空闲的时间来读(wan)书(shua)了。今天,他有t分钟的空闲时间来读书。因此,他跑到了图书馆开始他的读书大计。图书馆中有n本书,编号从1~nxyb读完每本书所花的时间为ai分钟。

xyb决定从随机的一本书开始读,然后一本接一本的读下去。比如,假设xyb决定从第i本书开始读,那么他的读书顺序编号就是i+1i+2...如果他把自己的空闲时间花光了,那他就不会再读下去了。所以,xyb想请你帮他确定一下读的第一本书的编号,使得他所能读完的书的本数最大(若最后一本书他读不完,则这本书不能算进去),输出他所能读的书本数的最大值。

输入

第一行包含两个整数nt1<=n<=10^51<=t<=10^9——n表示图书馆的书本数,t表示xyb的空闲时间(分钟)。
第二行包含n个整数a1,a2,...,an1<=ai<=10^4),ai表示xyb读完第i本书所需时间(分钟)。

输出

输出一个整数,表示xyb所能读的书本数的最大值。

样例输入复制

4 5

3 1 2 1

样例输出1

3

样例输入复制

3 3

2 2 3

样例输出2

1

解题思路:用数组存下前缀和,然后遍历过程中,二分往前找。

AC代码:

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <set>
#include <deque>
#include <functional>
#define maxn 100100
#define INF 0x3f3f3f3f
#define N 1010
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
ll a[maxn];
ll sum[maxn];
int main()
{
   int n, t;
   while (~scanf("%d%d", &n,&t))
   {
      sum[0] = 0;
      memset(a, 0, sizeof a);
      for (int i = 1; i <=n; i++)
      {
          scanf("%lld", &a[i]);
          sum[i] =sum[i - 1] + a[i];
      }
      int ans = 0;
      for (int i = 1; i <=n; i++)
      {
          ll res = sum[i] -t;
          if (res <= 0)
             ans =i;
          else
          {
             int l = 0, r = i;
             while (l <= r)
             {
                int mid = l + r>> 1;
                if (sum[mid] >=res)
                {
                   ans= max(ans, i - mid);
                   r= mid - 1;
                }
                else l = mid + 1;
             }
          }
      }
      printf("%d\n", ans);
   }
   return 0;
}


寻找flash

时间限制: 1000ms  内存限制: 128M

描述

众所周知,flash学长很喜欢玩游戏。今天,他想和大家玩一个捉迷藏的游戏。flash学长会藏在一个矩阵中并且可以使自己名字中的任意字母大写,现在看聪明的你能不能找到flash了。

(在这个矩阵中,如果将字母横着,竖着或者斜着连在一起能组成flash的任意组合便认为是找到了flash)

输入

输入有多组。每组第一个行为两个整数数nmn,m<=10),代表矩阵有nm列。接下来是一个n*m大小的矩阵。

输出

如果flash藏在这个矩阵中,输出yes,否则输出no

样例输入复制

2 5

FeeSh

alabb

1 5

falsh

样例输出1

yes

no

解题思路:

因为n和m很小,直接搜一下就行,dfs或者bfs

AC代码:

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <set>
#include <deque>
#include <functional>
#define maxn 100100
#define INF 0x3f3f3f3f
#define N 1010
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
char mp[20][20];
bool vis[20][20];
int dir[8][2] = { { 1, 0 },{ 0, 1 },{ -1, 0 },{0, -1 },{ -1, -1 },{ -1, 1 },{ 1, -1 },{ 1, 1 } };
int n, m, flag;
struct node
{
   int x, y, state;
   node(int a, int b, int c) {
      x = a;
      y = b;
      state = c;
   }
};
bool judge(int x, int y,int state)
{
   if (state == 2)
      return mp[x][y] == 'L' || mp[x][y] == 'l';
   else if (state == 3)
      return mp[x][y] == 'A' || mp[x][y] == 'a';
   else if (state == 4)
      return mp[x][y] == 'S' || mp[x][y] == 's';
   return mp[x][y] == 'H' || mp[x][y] == 'h';
}
void bfs(int sx, int sy)
{
   memset(vis, 0, sizeof(vis));
   queue<node> q;
   q.push(node(sx, sy, 1));
   while (!q.empty())
   {
      node cur = q.front();
      q.pop();
      if (cur.state == 5)
      {
          flag = 1;
          return;
      }
      vis[cur.x][cur.y] = 1;
      for (int i = 0; i <8; i++)
      {
          int dx = cur.x + dir[i][0];
          int dy = cur.y + dir[i][1];
          int state = cur.state + 1;
          if (dx >= 0&& dy >= 0 && dx < n && dy < m &&!vis[dx][dy])
          {
             if (judge(dx, dy, state))
                q.push(node(dx, dy, state));
          }
      }
   }
}
int main()
{
   while (~scanf("%d%d", &n,&m))
   {
      memset(mp, 0, sizeof(mp));
      for (int i = 0; i <n; i++)
          scanf("%s", mp[i]);
      flag = 0;
      for (int i = 0; i < n&& !flag; i++)
          for (int j = 0; j < m&& !flag; j++)
             if (mp[i][j] == 'F' || mp[i][j] == 'f')
                bfs(i, j);
      if (flag)
          puts("yes");
      else
          puts("no");
   }
   return 0;
}


知山知水,树木树人

时间限制: 1000ms  内存限制: 256M

描述

作为一名北林学子,知山知水,树木树人的校训肯定是牢记心中的。xyb也牢记这点。现在,他就在研究k叉树的问题。

对于k叉树,xyb给出了他自己的定义:

1.每个节点(除叶子节点外)都有k个子节点;

2.每条边都具有权值,每个节点下的第i条边的权值为i

例如,如果是一棵3叉树:

此刻,xyb提出了一个有趣的问题:从根节点出发,有多少条路径的权值和(即这条路径上所有的权值加起来)是等于n的,且这些路径还要满足一个条件,即经过的所有边,至少有一条边的权值是大于等于d的。

现在这个问题交给你来解决吧,由于路径数可能会非常大,输出时请对1000000007 (10^9+7)取模。(即%1000000007

输入

输入为一行。包括三个整数nkd1<=nk<=1001<=d<=k),用空格隔开。

输出

输出为一行。即满足条件的路径数对1000000007取模的结果。

样例输入复制

3 3 2

样例输出1

3

样例输入复制

3 3 3

样例输出2

1

样例输入复制

4 3 2

样例输出3

6

样例输入复制

4 5 2

样例输出4

7

解题思路:

dp[i][j],i存到和,j==0时,表示到i为止,还没出现过>=d的数,反之,j==1时,则出现过。

然后每层dp一下,状态转移为:

if(j>=d)

dp[i][1]=(dp[i][1]+dp[i-j][0]+dp[i-j][1])%mod

else

dp[i][0]=(dp[i][0]+dp[i-j][0])%mod

dp[i][1]=(dp[i][1]+dp[i-j][1])%mod

AC代码:

#include <bits/stdc++.h>
#define maxn 100100
#define INF 0x3f3f3f3f
#define N 1010
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
ll dp[110][2];
int main()
{
   int n, k, d;
   while (~scanf("%d%d%d%d", &n,&k, &d))
   {
      memset(dp, 0, sizeof(dp));
      dp[0][0] = 1;
      for (int i = 1; i <=n; i++)
      {
          for (int j = 1; j <=min(k, i); j++)
          {
             if (j >= d)
                dp[i][1]= (dp[i][1] + dp[i - j][0] + dp[i - j][1]) % mod;
             else
             {
                dp[i][1]= (dp[i][1] + dp[i - j][1]) % mod;
                dp[i][0]= (dp[i][0] + dp[i - j][0]) % mod;
             }
          }
      }
      cout << dp[n][1] % mod << endl;
   }
   return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值