您的位置:首页 > 其它

NEU 2016年2月月赛总结

2016-02-13 21:49 531 查看
由于时间不凑巧缺席了这次月赛有点可惜,过了这么久终于有时间补一补了,感觉除了5个水题EF都值得做做。嗯好今天开始又要好好做人了!!!!!


问题 A: The Singles

时间限制: 1 Sec  内存限制: 128 MB
提交: 204  解决: 50

[提交][状态][讨论版]


题目描述

The Signals’ Day has passed for a few days. Numerous sales promotion campaigns on the shopping sites make us forget that 11.11 is the Signals’ Day. So we should do something to enhance the concept of Singles’ Day.

Let’s give a number a, you should find the minimum number n only consist of digit 1(ie. 111,11111…) which can be divided by a. If the number exist, you should output "Singles' Day is on n.", otherwise you should output "There
is no Singles' Day!".


输入

Several test cases.

For each test case:

Input is a integer a(1<=a<=1000000),as described above.


输出

For each test case:

Output "Singles' Day is on n." or  "There is no Singles' Day!" in one line.


样例输入

1
2
3


样例输出

Singles' Day is on 1.
There is no Singles' Day!
Singles' Day is on 111.


很简单的数学水题,题意是给你一个数字a,求一个最小的各个位上都是1的数使得这个数能够整除a。

由于a范围比较小,我们可以考虑需要多少个1,然后首先用1模a,如果结果不是0,那么结果*10+1,这样的效果相当于给原来的数字后面添上一个1。如此循环直到这个数变成了一个出现过的数,显然这样就不存在解,否则答案就是1后面*10的次数个1。

#include <iostream>
#include <cmath>
#include <cstdlib>
#include <time.h>
#include <stack>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define maxn 1111111

long long a;
bool vis[maxn];
long long ans[maxn], cnt;

int main () {
while (scanf ("%lld", &a) == 1) {
cnt = 0;
memset (vis, 0, sizeof vis);
long long num = 1;
while (1) {
cnt++;
num = num%a;
if (num == 0)
break;
if (vis[num]) {
printf ("There is no Singles' Day!\n");
goto out;
}
vis[num] = 1;
num = num*10+1;
}
printf ("Singles' Day is on ");
for (int i = 0; i < cnt; i++) {
printf ("1");
}
printf (".\n");
out: ;
}
return 0;
}



问题 B: 全球变暖

时间限制: 2 Sec  内存限制: 128 MB
提交: 142  解决: 22

[提交][状态][讨论版]


题目描述

由于全球变暖,岛国S的沿岸的海水不断上涨,形式岌岌可危。

S国的地图是由n*m个网格组成的,网格由.和#组成,#代表的区域是陆地,.和地图外面全是海水。

每天,海水将侵蚀相邻的陆地,即如果陆地与海水相邻的话,第二天就会变成海水。这里面的两块相邻表示两块之间公用一条边。

比如S国的地图是这样的:

..###...

..###...

..###...

...##...

..######

..######

...#####

那么一天后,S国就变成了这样:

........

...#....

...#....

........

...##...

...####.

........

这种悲剧每天都在发生,再过1天S国就将被海水吞没。

现在S国的领导想知道t天后S国将变成什么样,有几块岛屿。。 如果两块陆地属于同一岛屿,当且仅当两块陆地相邻。

比图上面1天后S的地图中有两块岛屿。


输入

多组样例数入(样例不多)。

第一行是n,m,t,题目中已描述。(1<=n,m,t,<=2000)

然后是一个n行m列的S国地图,由.和#组成。


输出

第一行一个整数x表示岛屿数。

接下来n行画出t天后S国的地图。


样例输入

7 8 1
..###...
..###...
..###...
...##...
..######
..######
...#####


样例输出

2
........
...#....
...#....
........
...##...
...####.
........


一眼bfs题,算是5道水题里过得比较少的。

题意是给你一个地图#表示陆地 .表示海洋,陆地之间上下左右是连在一起的,每一天海洋都会使得它的上下左右变成陆地,然后要画出t天后的地图并且求出联通块有多少个。

嗯好我只要把地图画出来就好了。把所有的海洋点扔到队里里面。注意地图外都是海洋,所以我加了一圈的海洋点。然后从海洋点出发bfs,每次bfs的时候记录一下到达他的步数,超过t步的就不用放到队里里面;否则#变成.。

画出最终的地图后dfs一记就好了。

复杂度O(nm)。

#include <iostream>
#include <cmath>
#include <cstdlib>
#include <time.h>
#include <stack>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define maxn 2111
#define move Move

struct node {
int x, y;
int step;
bool operator < (const node &a) const {
return step > a.step;
}
};
bool vis[maxn][maxn];
queue <node> gg;
int n, m, t;
char mp[maxn][maxn];
const int move[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

bool legal (int x, int y) {
if (x < 1 || x > n || y < 1 || y > m)
return 0;
return 1;
}

void bfs () {
while (!gg.empty ()) {
node now = gg.front (); gg.pop ();
for (int i = 0; i < 4; i++) {
node next = now;
next.x += move[i][0];
next.y += move[i][1];
if (!legal (next.x, next.y))
continue;
else if (vis[next.x][next.y])
continue;
else {
int ss = next.step + 1;
if (ss > t)
continue;
else {
gg.push ((node){next.x, next.y, ss});
mp[next.x][next.y] = '.';
vis[next.x][next.y] = 1;
}
}
}
}
}

void dfs (int x, int y) {
vis[x][y] = 1;
for (int i = 0; i < 4; i++) {
int xx = x+move[i][0];
int yy = y+move[i][1];
if (legal (xx, yy) && !vis[xx][yy]) {
if (mp[xx][yy] == '#')
dfs (xx, yy);
}
}
}

int get () {
memset (vis, 0, sizeof vis);
int ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (!vis[i][j] && mp[i][j] == '#') {
ans++;
dfs (i, j);
}
}
}
return ans;
}

int main () {
while (scanf ("%d%d%d", &n, &m, &t) == 3) {
memset (mp, 0, sizeof mp);
while (!gg.empty ())
gg.pop ();
for (int i = 0; i <= m+1; i++) {
gg.push ((node){0, i, 0});
gg.push ((node){n+1, i, 0});
}
for (int i = 1; i <= n; i++) {
gg.push ((node){i, 0, 0});
gg.push ((node){i, m+1, 0});
}
memset (vis, 0, sizeof vis);
for (int i = 1; i <= n; i++) {
scanf ("%s", mp[i]+1);
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (mp[i][j] == '.') {
gg.push ((node){i, j, 0});
vis[i][j] = 1;
}
}
}
if (t >= (min (n, m)+1)/2) { //剪枝
printf ("0\n");
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
printf (".");
}
printf ("\n");
}
continue;
}
bfs ();
int ans = get ();
printf ("%d\n", ans);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
printf ("%c", mp[i][j]);
}
puts ("");
}
}
return 0;
}



问题 C: H-Index

时间限制: 1 Sec  内存限制: 128 MB
提交: 210  解决: 55

[提交][状态][讨论版]


题目描述

Given an array of citations (each citation is a non-negative integer) of a researcher, write a function to compute the researcher's h-index.

According to the definition of h-index on Wikipedia: "A scientist has index h if h of his/her N papers have at least h citations each, and the other N − h papers have no more than h citations
each."

For example, given citations = [3, 0, 6, 1, 5], which means the researcher has 5 papers in total and each of them had received 3, 0, 6, 1, 5 citations respectively. Since the researcher has 3 papers with at least 3 citations
each and the remaining two with no more than 3 citations each, his h-index is 3.

Note: If there are several possible values for h, the maximum one is taken as the h-index.


输入

First line is a non-negative integer T(0 < T <= 10) which indicates there are T testcases.

Then there is a non-negative integer n(0 < n <= 10000) which indicates the length of the citations.

After that follows n non-negative integers arr[i] (0 <= arr[i] <= 3 * n)


输出

Output the h-index


样例输入

1
5
3 0 6 1 5


样例输出

3


阅读题。题意有点绕,但是掩盖不了超级大水题的事实。

你需要求一个最大的h使得n个值中有h个数>=h并且有n-h个数<=h。

一看数据范围,暴力!

#include <iostream>
#include <cmath>
#include <cstdlib>
#include <time.h>
#include <stack>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define maxn 11111

int n;
long long a[maxn];

bool cmp (const long long &a, const long long &b) {
return a > b;
}

int main () {
int t;
scanf ("%d", &t);
while (t--) {
scanf ("%d", &n);
for (int i = 1; i <= n; i++) {
scanf ("%lld", &a[i]);
}
a[n+1] = -1;
sort (a+1, a+1+n, cmp);
long long ans = -1;
for (long long h = 0; h <= n; h++) {
if (a[h] >= h && a[h+1] <= h) {
ans = max (ans, h);
}
}
printf ("%lld\n", ans);
}
return 0;
}



问题 D: Sum of All Integer Numbers

时间限制: 1 Sec  内存限制: 128 MB
提交: 155  解决: 86

[提交][状态][讨论版]


题目描述

Your task is to find the sum of all integer numbers lying between 1 and N inclusive.


输入

There are multiple test cases.

The input consists of a single integer N that is not greater than 10000 by it's absolute value.


输出

Output a single integer number that is the sum of all integer numbers lying between 1 and N inclusive in one line.


样例输入

3
-3


样例输出

6
-5


求闭区间1-n之间的数的和。

#include <iostream>
#include <cmath>
#include <cstdlib>
#include <time.h>
#include <stack>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

int main () {
long long n;
while (scanf ("%lld", &n) == 1) {
if (n >= 1) {
printf ("%lld\n", (1+n)*n/2);
}
else
printf ("%lld\n", (1+n)*(2-n)/2);
}
return 0;
}


问题 E: All Pair Shortest Path

时间限制: 8 Sec  内存限制: 128 MB
提交: 42  解决: 8

[提交][状态][讨论版]

题目描述

Bobo has a directed graph G with n vertex labeled by 1,2,3,..n.

Let D(i,j) be the number of edges from vertex i to vertex j on the shortest path.

If the shortest path does not exist,then D(i,j)=n.

Bobo would like to find the sum of  D(i,j)*D(i,j) for all 1<=i<=n and 1<=j<=n.

输入

There are no more than 5 test cases.

The first line contains an integer n(1<=n<=1000).

The i-th of the following n lines contains n integers g(i,1),g(i,2),..g(i,n).

If there is an edge from i to j,then g(i,j)=1,otherwise g(i,j)=0;

输出

An integer denotes the sum of D(i,j)*D(i,j) for all 1<=i<=n and 1<=j<=n.

样例输入

3

010

001

100

2

10

01

样例输出

15

8


题意是给你一个01矩阵表示的有向图,D(i,j)表示i->j的最短路中的边数,求所有的D(i,j)*D(i,j)的和。

很容易想到一个n^3的做法:枚举每个点,从这个点出发进行一次bfs,bfs时每次取队首点,然后从队首点出发遍历寻找没有访问过的能够到达的点,那源点到这个点的距离就是源点到队首点的距离+1,最后结果加加。

那么我们再次基础上优化一下,我们每次取队首点无非是想找到某个没有访问过的点判断这个点是不是和队首点相连,和上面的方法相比我们少了很多访问过的点的遍历,于是我们只需要用set维护源点没有到达的点的集合即可。

tip:不要再迭代器循环里面删除set元素,用一个数组存下来需要删除的元素然后循环结束了一次性删除。

#include <iostream>
#include <cmath>
#include <cstdlib>
#include <time.h>
#include <stack>
#include <cstring>
#include <algorithm>
#include <queue>
#include <set>
using namespace std;
#define maxn 1111

int n;
char mp[maxn][maxn];
bool vis[maxn];
int que[maxn], tou, wei;
long long d[maxn];
set <int> gg;//哪些点没有访问
int del[maxn], cnt;//需要被删除的点
set <int>::iterator it;

long long bfs (int s) {
long long ans = 0;
memset (vis, 0, sizeof vis);
memset (d, -1, sizeof d);
d[s] = 0; vis[s] = 1;
tou = wei = 0;
gg.clear ();
for (int i = 0; i < n; i++) {
if (i == s)
continue;
else if (mp[s][i] == '1') {
vis[i] = 1;
que[wei++] = i;
d[i] = 1;
}
else {
gg.insert (i);
}
}

while (tou < wei && !gg.empty ()) {
int u = que[tou]; tou++;
int ss = d[u];
cnt = 0;
for (it = gg.begin (); it != gg.end (); it++) {
int v = *it;
if (mp[u][v] == '1') {
que[wei++] = v;
d[v] = ss+1;
vis[v] = 1;
del[cnt++] = v;
}
}
for (int i = 0; i < cnt; i++)
gg.erase (del[i]);
}

for (int i = 0; i < n; i++) {
if (d[i] == -1) {
ans += n*n;
}
else ans += d[i]*d[i];
}
return ans;
}

int main () {
while (scanf ("%d", &n) == 1) {
for (int i = 0; i < n; i++) {
scanf ("%s", mp[i]);
}
long long ans = 0;
for (int i = 0; i < n; i++) {
ans += bfs (i);
}
printf ("%lld\n", ans);
}
return 0;
}


问题 F: Sort It

时间限制: 6 Sec  内存限制: 128 MB
提交: 16  解决: 3

[提交][状态][讨论版]

题目描述

You are given a permutation of length n:p1,p2,...pn.Consider arrays of length n with possibly equal number from 1 to n.

If after rearrange elements of the array in the order of “all numbers equal to p1,all numbers equal to p2...all numbers equal to pn”,

the array become non-decreasing,then we call the array is sortable by p.

Calculate the total number of arrays that are sortable by p.

As the answer can be very large,output it after module 1e9+7.

输入

Several test cases.

The first line contains a single integer n(1<=n<=2000),the length of permutation.

The second line contains n distinct integers p1,p2,..pn(1<=pi<=n).

输出

Output a singe number -- the answer to the problem module 1e9+7.

样例输入

2

2 1

3

2 1 3

样例输出

2

15


数据结构+DP

题意写的比较难懂而且有些不严谨,但是题目还是很经典的。
题意是给你一个1-n的排列p,然后问你有多少个长度为n的数列a(a里面的元素属于[1,n])满足把a按照如下规则重新排列后a为非递减:

把a中所有等于p[1]的数放到最前面,a中所有等于p[2]的放到之后,所有等于p[3]的放到之后。。。所有等于p
的放到最后面。

这是经典的DP优化题,这类题目基本思路是构造出一个n^3的DP然后通过某种数据结构优化到n^2lgn。

之前在15年南阳CCPC做到过一道类似的题目,链接在这:点击打开链接

在构造DP之前需要知道i个不同的数排k个位置所有的方案数,简单的排列组合似乎无法解除于是考虑这样的DP,DP[i][j]表示i个不同的数排j个位置所有的方案数,我们考虑第一位的数字,如果这个数字不同于后面所有的数字,那么后面的数字就是i-1个数排j-1位;否则就是i个数排j-1位。因为第一个数字可以是任意的i个数之一,那么转移方程很明显,DP[i][j]=(DP[i-1][j-1]+DP[i][j-1])*i。这一部分的复杂度是O(n*n),恩,可以接受。

然后就是计数。因为重排列之后非递减,所以我们选择的数字在原排列中必须是一个非递减的序列,也就是原排列的任意上升子序列都能构成若干个可行解。所以我们需要找到所有的上升子序列,注意到上升子序列的长度影响了最终的结果(长度决定多少个不同的数排n位)。假设DP[i][j]表示以下标i结尾,长度为j的上升子序列个数,那么有下面的转移方程DP[i][j] = Σ(DP[k][j-1]),其中k<i并且a[k]<a[i]。然后我们需要把这个n^3的DP优化到n^2lgn。

对于某一个数i,我们无非是想知道比i小的所有的DP[k][j]的值,所以我们把原排列按照大小重排序,然后从小到大遍历,每次改变的都是这个数原位置之后的DP和,统计时向前统计,这样就可以避免小的数位置在大的数之后造成的影响。每次add和sum用一个树状数组或者线段树维护。

#include <iostream>
#include <cmath>
#include <cstdlib>
#include <time.h>
#include <stack>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 2111
#define mod 1000000007

long long cnt[maxn][maxn];//i个不同的数排j个空格 所有的情况数
struct node {
long long num;
int pos;
bool operator < (const node &a) const {
return num < a.num;
}
}a[maxn];
long long c[maxn][maxn];
long long dp[maxn][maxn];//排序后第i个数结尾 长度为j的上升序列个数
int n;

void init () {
memset (cnt, 0, sizeof cnt);
for (int i = 1; i <= 2000; i++) {
cnt[1][i] = 1;
}
for (int i = 2; i <= 2000; i++) {
for (int j = i; j <= 2000; j++) {
cnt[i][j] = (cnt[i][j-1]*i%mod + cnt[i-1][j-1]*i%mod) % mod;
}
}
return ;
}

int lowbit (int x) {
return x & (-x);
}

void add (int pos, int l, long long num) {
for (int i = pos; i <= n; i += lowbit (i)) {
c[i][l] += num;
c[i][l] %= mod;
}
return ;
}

long long sum (int pos, int l) {
long long ans = 0;
for (int i = pos; i > 0; i -= lowbit (i)) {
ans += c[i][l];
ans %= mod;
}
return ans;
}

int main () {
init ();
while (scanf ("%d", &n) == 1) {
long long gg = 0;
memset (dp, 0, sizeof dp);
memset (c, 0, sizeof c);
for (int i = 1; i <= n; i++) {
scanf ("%lld", &a[i].num);
a[i].pos = i;
}
sort (a+1, a+1+n); //cout << ".." << endl;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) { //cout << "/" << endl;
if (j == 1) {
dp[i][j] = 1;
add (a[i].pos+1, 1, 1);
}
else {
long long cur = sum (a[i].pos, j-1);
dp[i][j] = cur;
add (a[i].pos+1, j, dp[i][j]);
}
gg += dp[i][j]*cnt[j]
%mod;
gg %= mod;
}
}
/*for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cout << dp[i][j] << " ";
} cout << endl;
}*/
printf ("%lld\n", gg);
}
return 0;
}


问题 G: Mirror Rice Cake

时间限制: 1 Sec  内存限制: 128 MB
提交: 136  解决: 67

[提交][状态][讨论版]

题目描述

Mirror Rice Cake (a stack of rice cakes) is a famous Japanese food that is used for celebrating the new year.

Snuke has N rice cakes to create a Mirror Rice Cake.The weight of the i-th cake is an integer Ai.

He wants to create a Mirror Rice Cake by choosing some of these cakes and stacking them in some order.

It must satisfy the following constraint:for each cake in the stack,the total weight of all rices above it must be strictly smaller than its own weight.

Compute the maximum number of rice cakes he can use to create a Mirror Rice Cake.

输入

Several test cases.

First line contains a number N(1<=n<=1000).

Then follows N lines denote the weight of the i-th cake Ai(1<=Ai<=1e9).

输出

A single number denote the answer.

样例输入

5320586

样例输出

3

提示

In the sample test,you can put 3,5,20 from top to bottom.

水题,贪心。给你n个数,最多能排多少个数能够使得每个数都比它前面的所有的数大。
排个序贪心扫一遍即可。

#include <iostream>
#include <cmath>
#include <cstdlib>
#include <time.h>
#include <stack>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define maxn 1111

int main () {
long long n;
long long a[maxn];
while (scanf ("%lld", &n) == 1) {
for (int i = 1; i <= n; i++) { //cout << ".." << endl;
scanf ("%lld", &a[i]);
}
sort (a+1, a+1+n);
long long sum = 0, ans = 0;
for (int i = 1; i <= n; i++) { //cout << ".." << endl;
if (a[i] > sum) {
ans++;
sum += a[i];
}
}
printf ("%lld\n", ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: