SCUT 2014 春季选拔第一场个人题解

<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: rgb(255, 255, 255);">第一场</span>

A.回文串

1000ms   /  65536KB   /   C, C++ or JAVA

Author: dovegx   /   Editor: dovegx

Description

据说字符串都是很难的,可是芳姐最喜欢了,最近他迷上了回文字符串,回文串正着读和反着读是一样的,比如 abba, aaaa都是回文串, abbc不是回文串。芳姐想知道如果把整个字符串拆散重新组合,能组成的最长的回文串。原串字母不一定全部用上。

Input Description

多样例(大约10个),每个样例一行仅有小写字母组成的字符串,字符创长度不大于100000

Output Description

每个样例输出一个整数,表示能组成的最长回文串的长度

Sample Input

abab

abc

Sample Output

4

1

开一个数组a[26]保存字母的个数,每两个字母构成前后的回文,最后判断是否存在多出一个字母放置在回文数列的最中间

 

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <set>
#include <ctime>
#include <queue>
#include <numeric>
#include <list>
#pragma warning (default : 4996)
using namespace std;
 
#define eps 1e-8
#define LL long long
#define ULL unsigned longlong
#define mod 1000000007
#define MP make_pair
 
int a[26];
char s[100010];
int main()
{
   while (gets(s))
   {
      memset(a, 0, sizeof(a));
      int ans = 0;
      int len = strlen(s);
      for (int i = 0; i < len; i++) {
         a[s[i] - 'a']++;
      }
      for (int i = 0; i < 26; i++) {
         while (a[i] >= 2) {a[i] -= 2; ans += 2; }
      }
      for (int i = 0; i < 26; i++) {
         if (a[i] == 1) {ans++; break; }
      }
      printf("%d\n", ans);
   }
   return 0;
}


 

B.Combination

1000ms   /  65536KB   /   C, C++ or JAVA

Author:   /   Editor: dovegx

Description

      Ilya plays a card game by the following rules.
       A player has several cards. Each card contains twononnegative integers inscribed, one at the top of the card and one at thebottom. At the beginning of the round the player chooses one of his cards toplay it. If the top of the card contains number ai, and the bottom containsnumber bi, then when the player is playing the card, he gets ai points and alsogets the opportunity to play additional bi cards. After the playing the card isdiscarded.
       More formally: let's say that there is a counter ofthe cards that can be played. At the beginning of the round the counter equalsone. When a card is played, the counter decreases by one for the played cardand increases by the number bi, which is written at the bottom of the card.Then the played card is discarded. If after that the counter is not equal tozero, the player gets the opportunity to play another card from the remainingcards. The round ends when the counter reaches zero or the player runs out ofcards.
       Of course, Ilya wants to get as many points aspossible. Can you determine the maximum number of points he can score providedthat you know his cards?     

Input Description

Thefirst line contains a single integer n( 1<=n<=1000) — the number of cardsIlya has.
Each of the next n lines contains two non-negative space-separated integers — ai and bi( 0 <= ai, bi <= 10^4 )— thenumbers, written at the top and the bottom of the i-th card correspondingly.

Output Description

Printthe single number — the maximum number of points you can score in one round by thedescribed rules.

Sample Input

2

1 0

2 0

3

1 0

2 0

0 2

Sample Output

2

3

贪心,先取bi最大的,以此来增加取卡片的次数。如果有多个相同的bi,选择ai最大的,以此来最大化分数。

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#pragma warning (default : 4996)
using namespace std;
 
struct cards {
   int a, b;
   bool operator < (constcards &oth)const {
      return b > oth.b || (b == oth.b && a > oth.a);
   }
}c[1005];
int main()
{
   int n;
   while (scanf("%d", &n) == 1)
   {
      for (int i = 0; i < n; i++) {
         scanf("%d%d", &c[i].a,&c[i].b);
      }
      sort(c, c + n);
      int couter = 1, cnt = 0, ans = 0;
      while (couter > 0 && cnt < n) {
         ans += c[cnt].a;
         couter--;
         couter += c[cnt++].b;
      }
      printf("%d\n", ans);
   }
   return 0;
}


 

 

C.单峰排序

1000ms   /  65536KB   /   C, C++ or JAVA

Editor: dovegx

Description

一个n的全排列A[i]是单峰的,当且仅当存在某个x使得A[1]<A[2]<...<A[x]>A[x+1]>...>A[n]。
例如,对于9的全排列,125798643是一个单峰排列,123456789也是一个单峰排列,但356298741就不是。
试求n的单峰全排列的个数。

Input Description

输入一个数n。n小于max_int64

Output Description

输出n的全排列中单峰排列的个数。
  由于这个数可能很大,因此你只需要输出它mod 1234567的值。

Sample Input

3

Sample Output

4

 

经过少量演算,得到的规律是 ans[n] = 2^(n-1),因为n<max_int64,考虑到要用快速幂.

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <set>
#include <ctime>
#include <queue>
#include <numeric>
#include <list>
#pragma warning (default : 4996)
using namespace std;
 
#define eps 1e-8
#define LL long long
#define ULL unsigned longlong
#define mod 1000000007
#define MP make_pair
 
#define mod1 1234567
LL ans, n;
LL qm(LLx) {
   LL r = 1, base = 2;
   while (x != 0) {
      if (x % 2 == 1) r = r * base %mod1;
      base = base * base % mod1;
      x >>= 1;
   }
   return r;
}
int main()
{
   while (scanf("%lld", &n) == 1)
   {
      ans = qm(n - 1);
      printf("%lld\n", ans);  //华工是用lld读long long ,卡了好久=。=。
   }
   return 0;
}


 

D.Escape

3000ms   /  65536KB   /   C, C++ or JAVA

Editor: dovegx

Description

After the battleagianst BOSS smallMing,dovegx finds the island start sinking into sea at aconstant speed(1 unit per minute).surely,dovegx has to run,run and run,untilreaching his boat at the coast. 
The island is described as a matrix of n*m grids,each has a height.At any timea grid with height h<0 must be filled with water.At the beginning,dovegxstays at grid (1,1),also the top left corner of the island,and the boatis(n,m).Assume dovegx now locates at (i,j) he can move to(i+1,j),(i-1,j),(i,j+1)or(i,j-1) at next minute if no water there,also he canstay still.(note,the sea around the island has many many water..)

Input Description

Thereare multiple cases.
The first line of the input contains n,m.(1<=n,m<=1000).Next n lines eachcontain m integers.aij is the height of grid(i,j).(-10000<=aij<=10000).It´s guaranteed,a11>=0.

Output Description

Tellif dovegx can escape from the island,print "Yes"and the minimalminutes he need to reach his boat(arrive at grid(n,m)) if he can.print only"No" if he cannot.

Sample Input

2 2

1 1

1 2

 

3 3

1 2 3

1 2 3

1 2 3

Sample Output

Yes

2

No

广搜,妈蛋,卡MLE和WA好久。。原来是标记入队顺序的问题;

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#pragma warning (default : 4996)
using namespace std;
 
int dis[4][2] = { 1, 0,-1, 0, 0, 1, 0, -1 };
struct T {
   int val;
   int pre;
}a[1005][1005];
struct point {
   int x, y;
};
bool vis[1005][1005];
int n, m;
queue<point> que;
bool bfs()
{
   point init;
   init.x = 1; init.y = 1;
   que.push(init);    // 标记(1,1)入队。
   vis[1][1] = true;
   a[1][1].pre = 0;
   while (!que.empty()) {
      point loc = que.front(); que.pop();
      if (loc.x == n && loc.y == m)returntrue; //找到了就结束。
      for (int i = 0; i < 4; i++) {
         point nstat;
         nstat.x = loc.x + dis[i][0];
         nstat.y = loc.y + dis[i][1];
         a[nstat.x][nstat.y].pre =a[loc.x][loc.y].pre + 1;  // pre是标记第几步到达nstat;
         //下面判断是否合法,合法就入队。
         if(!vis[nstat.x][nstat.y] && (a[nstat.x][nstat.y].val -a[nstat.x][nstat.y].pre) >= 0 && nstat.x <= n && nstat.y<= m && nstat.x >= 1 && nstat.y >= 1) {
            que.push(nstat);
            vis[nstat.x][nstat.y] = true;//标记nstat入队
         }
      }
   }
   return false;
}
int main()
{
   while (scanf("%d%d", &n, &m) == 2) {
      for (int i = 1; i <= n; i++) {
         for (int j = 1; j <= m;j++) {
            scanf("%d", &a[i][j].val);
         }
      }
      memset(vis, 0, sizeof(vis));
      while (!que.empty()) que.pop();//多数据处理,要初始化队列。
      if (bfs()) {
         printf("Yes\n%d\n", a[n][m].pre);
      }
      else printf("No\n");
   }
   return 0;
}

E.CutString

2000ms   /  65536KB   /   C, C++ or JAVA

Editor: dovegx

Description

Given a strings, partition s such that every substring of the partition is a palindrome.
Find the minimum cuts needed for a palindrome partitioning of s.
For example, given s = "aab",
Output 1 since the palindrome partitioning ["aa","b"] couldbe produced using 1 cut.

Input Description

Inputcontains multiple test cases.
For each you are given a string s which length is less than 300 and onlycontains lowercases.

Output Description

Foreach output the minimum cuts needed for a palindrome partitioning of s.*//*/

Sample Input

aab

a

abacdcefe

Sample Output

1

0

2

 

题意:是给定一个字符串S,问你最少cut多少次,才能使得cut出来的子串都是回文串

题解:首先是扫描所有是回文串的子串,将他们存入一个vector里面,然后扫描这个vector,

如果其中两个在本来的串S中是连续的,就连接一条权为1的边;如果是起点子串,就和超级源点(编号为0)连一条权为0的边;如果是终点子串,就和超级终点(编号为vector.size()+1)连一条权为0的边。所以问题就转变成求这个图的最短路。

 

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <set>
#include <ctime>
#include <queue>
#include <numeric>
#include <list>
#include <functional>
 
 
using namespace std;
 
#define eps 1e-8
#define LL long long
#define ULL unsigned long long
#define mod 1000000007
#define MP make_pair
#define PII pair<int,int>
#define INF 0x3f3f3f3f
 
 
struct Node{
       string str;
       int id,from, to;  // id是赋予每个子串编号,from是起始位置,to是终止位置;
       Node(){}
       Node(string s, inti, int from, intto){
              str = s;
              id = i;
              this->from= from;
              this->to= to;
       }
};
 
const int mxn =305*305;
 
int first[mxn], nxt[mxn], vv[mxn], cost[mxn], e;
int d[mxn], vis[mxn];
 
void add(int u,int v,int c)  //加边函数;
{
       vv[e] = v; cost[e] = c; nxt[e] =first[u];
       first[u] = e++;
}
vector<Node>ivec;
 
void dij()  // 优先队列优化的dijkstra
{
       priority_queue<PII, vector<PII>,greater<PII> > q;
       memset(vis, 0, sizeof(vis));
       for (int i = 0; i <= ivec.size()+1; ++i) d[i] = (i == 0? 0 : INF);
       q.push(MP(d[0],0));
       while(!q.empty())
       {
              PII u =  q.top(); q.pop();
              intx = u.second;
              if(vis[x])continue;
              vis[x] = true;
              for(int i = first[x]; i != -1; i = nxt[i])
              {
                     inty = vv[i];
                     if(d[y]> d[x] + cost[i])
                     {
                            d[y] = d[x] +cost[i];
                            q.push(MP(d[y], y));
                     }
              }
       }
      
}
 
 
int main()
{
       string in;
       while(cin>> in)
       {
              ivec.clear();
              e = 0;
              int  id = 0;
              memset(first, -1, sizeof(first)); // 这几步都是初始化操作
              intn = in.length();
              for(int i = 0; i < n; ++i)  //扫描所有子串
              {
                     for(int  j =0; i - j >= 0 && i + j < n; ++j)
                     {
                            if (in[i-j] != in[i+j])break;
                            else
                            {
                                   ivec.push_back(Node(in.substr(i-j,i+j+1), ++id, i-j, i+j));  // 保存回文子串信息
                            }
                     }
                     for(int  j =0; i - j >= 0 && i + j + 1 < n; ++j)
                     {
                            if (in[i-j] != in[i+j + 1])break;
                            else
                            {
                                   ivec.push_back(Node(in.substr(i-j,i+j+2), ++id, i-j, i+j+1)); // 保存回文子串信息
 
                            }
                     }
              }
              for(int i = 0; i < ivec.size(); ++i)
              {
                     if(ivec[i].from == 0) add(0, ivec[i].id, 0);  //超级源点
                     if(ivec[i].to == n - 1) add(ivec[i].id, ivec.size() + 1, 0); // 超级终点
                     for(int j = 0; j < ivec.size(); ++j)
                     {
                            if (ivec[i].to + 1 == ivec[j].from)
                            {
                                   add(ivec[i].id,ivec[j].id, 1);
                            }
                     }
              }
              dij();
              printf("%d\n",d[ivec.size()+1]); 
       }
       return 0;
}


 

G.蜡烛是我的!

1000ms   /  65536KB   /   C, C++ or JAVA

Editor: dovegx

Description

小明玩炉石传说中毒过深,以至于某天晚上大叫一声“蜡烛是我的!”。。现在有k根蜡烛,每根蜡烛在燃烧之后都会剩下一个蜡烛头。已知每m个蜡烛头又可以合成一个新的蜡烛,现在我给你k和m,请你帮我算算这k根蜡烛最多能提供多久的光明?(每根蜡烛可以燃烧一小时)

Input Description

第一行有一个正整数T,表示样例数(T<=100)
对于每一个case,有2个正整数,k和m (k<=1000,1<m<=100)

Output Description

对于每一个case,输出一行,即最大照明时间

Sample Input

1

4 2

Sample Output

7

水的一笔。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <set>
#include <ctime>
#include <queue>
#include <numeric>
#include <list>
#pragma warning (default : 4996)
using namespace std;
 
#define eps 1e-8
#define LL long long
#define ULL unsigned longlong
#define mod 1000000007
#define MP make_pair
 
 
int main()
{
   int t;
   int k, m;
   int ans;
   int left;
   scanf("%d", &t);
   while (t--) {
      scanf("%d%d", &k, &m);
      ans = left = k;
      while (left >= m) {
         left -= m - 1;
         ans++;
      }
      printf("%d\n", ans);
   }
   return 0;
}


 

H.解方程

1000ms   /  65536KB   /   C, C++ or JAVA

Editor: dovegx

Description

解方程 x1+x2+x3+x4+….+xn=m. m是常数,xi是未知数,求这个方程有多少组非负解。

Input Description

多样例,
每个样例是一个方程,方程之间没有空格或者其他无关符号,具体格式看样例输入
未知数最多100个,m的值不超过100。

Output Description

因为答案会很大,输出结果模 10007

Sample Input

x1+x2=3

Sample Output

4

Hint

(0, 3 ), (3, 0),(1,2),(2,1)

 题解: 什么鸡鸡隔板法的,我也不知道,一直调都没过。。。

 

 

J.序列操作

1000ms   /  65536KB   /   C, C++ or JAVA

Editor: dovegx

Description

已知一个初始为0的序列长度为n,进行m组操作,每次操作将as……at增加k。

Input Description

第一行输入T表示有T个样例
每个样例第一行n, m( 0<n, m<=1000000)
接下来m行 s, t, k, 表示将as……at增加k。

Output Description

每个样例输出最终数列的和

Sample Input

2

3 2

1 1 1

1 3 1

2 1

1 2 1

Sample Output

4

2

你这么水,你爹地妈咪知道吗?

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <set>
#include <ctime>
#include <queue>
#include <numeric>
#include <list>
#pragma warning (default : 4996)
using namespace std;
 
#define eps 1e-8
#define LL long long
#define ULL unsigned longlong
#define mod 1000000007
#define MP make_pair
 
 
int main()
{
   int T, n, m;
   LL s, t, k;
   scanf("%d", &T);
   while (T--) {
      scanf("%d%d", &n, &m);
      LL sum = 0;
      while (m--) {
         scanf("%lld%lld%lld", &s, &t,&k);
         sum += (t - s + 1) * k;
      }
      printf("%lld\n", sum);
   }
   return 0;
}



 

I.集合

1000ms   /  65536KB   /   C, C++ or JAVA

Editor: dovegx

Description

在一个神秘领土里有N个城市,城市之间有道路相连,一共有M条道路。领土里面的城市分为两个帮派,黑派或者红派。有关部门说两个派必定会一起混乱,所以两个派就干起来了。他们首先集合人员,战斗之前黑派的人不能走到红派的城市,反之也不能。整个领土里的人尽可能地集合在一起。问最大的集合有多少人。

Input Description

多样例
第一行 N, M ( 0 < N <= 100, 0 < M < 5000 ).
接下来N行 xi, yi. xi = 0表示城市i为红派,x=1城市i为黑派,yi表示城市i的人口;
接下来M行 u, v 表示城市u和城市v相连,城市序号从1开始

Output Description

最大的集合人数

Sample Input

6 10

1 67

0 0

1 24

0 58

0 64

1 45

2 4

2 6

2 3

4 1

4 1

3 4

5 5

4 3

3 6

6 1

Sample Output

136

额,这是传说中的并查集。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#pragma warning (default : 4996)
using namespace std;
 
int pa[101];
int findset(inta) {
   return pa[a] !=a ? pa[a] = findset(pa[a]) :a;
}
int main()
{
   int n, m;
   int x[101], y[101];
   int xx, yy;
   bool vis[101];
   while (scanf("%d%d", &n, &m) == 2) {
      memset(vis, 0, sizeof(vis));
      for (int i = 1; i <= n; i++) {
         pa[i] = i;
      }
      for (int i = 1; i <= n; i++) {
         scanf("%d%d", &x[i],&y[i]);
      }
      for (int i = 1; i <= m; i++) {
         scanf("%d%d", &xx, &yy);
         if (x[xx] == x[yy])pa[findset(xx)] = findset(yy);//刚开始写pa[xx] = yy跪了。合并根节点。
      }
      int ans = -1;
      for (int i = 1; i <= n; i++) {
         if (vis[i] == true) continue;
         int sum = y[i];
         for (int j = i + 1; j <=n; j++) {
            if (x[i] != x[j]) continue;
            else
            {
                vis[j] = 1;
                if (findset(i) ==findset(j))
                   sum += y[j];
            }
         }
         ans = max(sum, ans);
      }
      cout << ans << endl;
   }
   return 0;
}


 

其实也可以用深搜做, 两个城市阵营相同且相通的就连一条边。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <set>
#include <ctime>
#include <queue>
#include <numeric>
#include <list>
#include <functional>
 
 
using namespace std;
 
#define eps 1e-8
#define LL long long
#define ULL unsigned long long
#define mod 1000000007
#define MP make_pair
#define PII pair<int,int>
#define INF 0x3f3f3f3f
 
#define mxn 105
 
vector<int> G[mxn]; //邻接表保存边
 
struct Node{
       int x;  //阵营
       int y;  //人口
       void in()
       {
              scanf("%d%d",&x, &y);
       }
}p[mxn];
 
int vis[mxn]; //深搜标记数组
int sum; //保存每次搜索的结果
int ans;
 
void dfs(int u)
{
       vis[u] = 1;   //标记已访问
       sum += p[u].y; // 加入当前节点人口
       int d =G[u].size();  
       for (int i = 0; i < d; ++i) //枚举遍历所有(u,v)边
       {
              intv = G[u][i];
              if(!vis[v])dfs(v);
       }
}
 
void init()  //初始化操作
{
       memset(vis, 0, sizeof(vis));
       for (int i = 0; i < mxn; ++i) G[i].clear();
       ans = 0;
}
void add(int u,int v)  //加入边,因为是无向边,所以要加入两次。
{
       G[u].push_back(v);
       G[v].push_back(u);
}
 
int main()
{
       int n, m;
       int u, v;
       while(~scanf("%d%d", &n, &m))
       {
              init();
              for(int i = 1; i <= n; ++i)    p[i].in();
              for(int i = 1; i <= m; ++i)
              {
                     scanf("%d%d", &u, &v);
                     if(p[u].x == p[v].x)  //两个城市阵营相同且相通的就连一条边。
                            add(u, v);
              }
              for(int i = 1; i <= n; ++i)  //遍历搜索
              {
                     if(!vis[i])
                     {
                            sum = 0;
                            dfs(i);
                            if(sum > ans) ans = sum;
                     }
 
              }
              printf("%d\n",ans);
       }
      
       return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值