Hdu 2015 Multi-University Training Contest7

1003

题面

Problem Description
Hotaru Ichijou recently is addicated to math problems. Now she is playing with N-sequence.
Let’s define N-sequence, which is composed with three parts and satisfied with the following condition:
1. the first part is the same as the thrid part,
2. the first part and the second part are symmetrical.
for example, the sequence 2,3,4,4,3,2,2,3,4 is a N-sequence, which the first part 2,3,4 is the same as the thrid part 2,3,4, the first part 2,3,4 and the second part 4,3,2 are symmetrical.

Give you n positive intergers, your task is to find the largest continuous sub-sequence, which is N-sequence.

Input
There are multiple test cases. The first line of input contains an integer T(T<=20), indicating the number of test cases.

For each test case:

the first line of input contains a positive integer N(1<=N<=100000), the length of a given sequence

the second line includes N non-negative integers ,each interger is no larger than 109 , descripting a sequence.

Output
Each case contains only one line. Each line should start with “Case #i: ”,with i implying the case number, followed by a integer, the largest length of N-sequence.

We guarantee that the sum of all answers is less than 800000.

Sample Input

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

Sample Output

Case #1: 9

题意

给一个长度为n(10^5)的序列,求一个最长的子序列,满足以下条件:
这个序列由三段组成,第一段与第二段对称,第一段与第二段相同。
比如:1 2 3 3 2 1 1 2 3。就是一个长度为9的串。

解析

一年前做过两道最长回文串的题,然后就忘得一干二净- -
最长回文串O(n)算法
这题就完全考这个算法的理解了。
先用manacher算法把每个位置的最长回文串找出来,然后枚举第二段的起点和长度,不断更新就行了。
枚举长度的时候相当于加个剪枝。

样例详解:
首先输入了一个串:

i0123456789
oldStr2344322344

接着将原串预处理,并由Manacher算法计算出每个下标下的最大回文串长度P[i]:

i012345678910111213141516171819202122
newStr-inf#2#3#4#4#3#2#2#3#4#4#inf
p[i]01212127212129212123211

由于题目要求所以应该从下标i应该从1开始枚举1,3,5,…的p[i],长度j也每次+=2去枚举p[i+j-1]这个位置#号的最大回文串,若当前长度j<=p[i + j - 1]的话,表示当前这个位置的回文串把前面的都包含进去了,所以更新最大值就行了。
最后由于我的长度是处理后的长度,为原来的2倍,所以/2*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 Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

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

int oldstr[maxn];
int newstr[maxn << 1];
int p[maxn << 1];

int Pre(int n)
{
    int head = -inf;
    int middle = -1;
    int end = inf;
    int len = 0;

    newstr[len++] = head;
    newstr[len++] = middle;
    for(int i = 0; i < n; i ++)
    {
        newstr[len++] = oldstr[i];
        newstr[len++] = middle;
    }
    newstr[len++] = end;
    return len;
}

int Manacher(int len)
{
    int MaxID = 0;
    int MaxL = 0;
    int id = 1;
    p[0] = 0;
    for(int i = 1; i < len; i ++)
    {
        if(MaxID > i)
            p[i] = min(p[2 * id - i], MaxID - i);
        else
            p[i] = 1;
        while(newstr[i - p[i]] == newstr[i + p[i]])
            p[i] ++;
        if(p[i] + i > MaxID)
        {
            MaxID = p[i] + i;
            id = i;
        }
        if(p[i] > MaxL)
        {
            MaxL = p[i];
        }
    }
    return MaxL - 1;
}

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    int ncase;
    int ca = 1;
    scanf("%d", &ncase);
    while (ncase--)
    {
        int n;
        scanf("%d", &n);
        for (int i = 0; i < n; i++)
        {
            scanf("%d", &oldstr[i]);
        }
        int len = Pre(n);
        Manacher(len);
        int ans = 1;
        for (int i = 1; i < len; i += 2)
        {
//            cout << p[i] << " ";
            for (int j = ans; j <= p[i]; j += 2)
            {
                if (j <= p[i + j - 1])
                {
                    ans = j;
                }
            }
        }
        ans = ans / 2 * 3;
        printf("Case #%d: ", ca++);
        cout << ans << endl;
    }
    return 0;
}

1005

题面

Problem Description
In this problem, we should solve an interesting game. At first, we have an integer n, then we begin to make some funny change. We sum up every digit of the n, then insert it to the tail of the number n, then let the new number be the interesting number n. repeat it for t times. When n=123 and t=3 then we can get 123->1236->123612->12361215.

Input
Multiple input.
We have two integer n (0<=n<=104 ) , t(0<=t<=105) in each row.
When n==-1 and t==-1 mean the end of input.

Output
For each input , if the final number are divisible by 11, output “Yes”, else output ”No”. without quote.

Sample Input

35 2
35 1
-1 -1

Sample Output

Case #1: Yes
Case #2: No

题意

给一个数n,按题中描述模拟t次。
问最后结果能不能被11整除。
当n=123 and t=3 时,123->1236->123612->12361215.

解析

直接模拟竟然能过。。。

整除11的数的性质是这个数奇数位的和 和 偶数位的和 的差能被11整除。
然后队友写超时了0 0.

代码

模拟:

#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 Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

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

int getSum(int x)
{
    int res = 0;
    while (x)
    {
        res += x % 10;
        x /= 10;
    }
    return res;
}

int wei(int x)
{
    int cnt = 0;
    while (x)
    {
        x /= 10;
        cnt++;
    }
    return cnt;
}

int fun(int x)
{
    int res = 1;
    for (int i = 0; i < x; i++)
    {
        res *= 10;
    }
    return res;
}

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
    #endif // LOCAL
    int n, t;
    int ca = 1;
    while (~scanf("%d%d", &n, &t))
    {
        if (n + t == -2)
            break;
        int sum = getSum(n);
        int num = n % 11;
        while (t--)
        {
            num = num * fun(wei(sum)) + sum;
            sum += getSum(sum);
            num %= 11;
        }
        if (num)
            printf("Case #%d: No\n", ca++);
        else
            printf("Case #%d: Yes\n", ca++);
    }
    return 0;
}

1007

题面

Problem Description
The reflected binary code, also known as Gray code after Frank Gray, is a binary numeral system where two successive values differ in only onebit (binary digit). The reflected binary code was originally designed to prevent spurious output from electromechanical switches. Today, Gray codes are widely used to facilitate error correction in digital communications such as digital terrestrial television and some cable TV systems.

这里写图片描述

Now , you are given a binary number of length n including ‘0’ , ’1’ and ‘?’(? means that you can use either 0 or 1 to fill this position) and n integers(a1,a2,….,an) . A certain binary number corresponds to a gray code only. If the ith bit of this gray code is 1,you can get the point ai.
Can you tell me how many points you can get at most?

For instance, the binary number “00?0” may be “0000” or “0010”,and the corresponding gray code are “0000” or “0011”.You can choose “0000” getting nothing or “0011” getting the point a3 and a4.

Input
The first line of the input contains the number of test cases T.

Each test case begins with string with ‘0’,’1’ and ‘?’.

The next line contains n (1<=n<=200000) integers (n is the length of the string).

a1 a2 a3 … an (1<=ai<=1000)

Output
For each test case, output “Case #x: ans”, in which x is the case number counted from one,’ans’ is the points you can get at most

Sample Input

2
00?0
1 2 4 8
????
1 2 4 8

Sample Output

Case #1: 12
Case #2: 15
Hint

https://en.wikipedia.org/wiki/Gray_code

http://baike.baidu.com/view/358724.htm

题意

给一个二进制数,其中包含?的地方可以是0,也可以是1。
然后问这个二进制数转换成格雷码,每位为1的权值相加最大为多少。

解析

模拟贪心。
开始的时候用前缀和求一直错一直错,然后突然发现其实中间的时候可以控制放弃最小权值的那个数。
然后又写,然后fr,to写晕了,换成了i,j。。。
然后又wa,一只wa,找不到原因。
然后全部推了重写,然后就过了,莫名其妙。。。
dp也行吧。。。

代码

#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 Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

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

char str[maxn];
int a[maxn];

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    int ca = 1;
    int ncase;
    scanf("%d", &ncase);
    while (ncase--)
    {
        scanf("%s", str);
        int n = strlen(str);

        for (int i = 0; i < n; i++)
        {
            scanf("%d", &a[i]);
        }

        int ans = 0;
        int i, j;
        for (i = 0; i < n; i++)
        {
            if (str[i] != '?')
                continue;

            int las, pre;
            int cnt = 0;
            if (i == 0)
                pre = 0;
            else
                pre = str[i - 1] - '0';

            for (j = i; j < n; j++)
            {
                if (str[j] == '?')
                    cnt++;
                else
                    break;
            }

            las = str[j] - '0';
            if (j == n)
            {
                for (; i < j; i++)
                    ans += a[i];
            }
            else if (las == pre)
            {
                if (cnt & 1)
                {
                    for (; i <= j; i++)
                        ans += a[i];
                }
                else
                {
                    int minn = inf;
                    for (; i <= j; i++)
                    {
                        ans += a[i];
                        minn = min(minn, a[i]);
                    }
                    ans -= minn;
                }
            }
            else
            {
                if (cnt & 1)
                {
                    int minn = inf;
                    for (; i <= j; i++)
                    {
                        ans += a[i];
                        minn = min(minn, a[i]);
                    }
                    ans -= minn;
                }
                else
                {
                    for (; i <= j; i++)
                        ans += a[i];
                }
            }
            i = j;
        }
        for (int i = 0; i < n; i++)
        {
            if (str[i] == '0')
            {
                if (i != 0 && str[i - 1] == '1')
                    ans += a[i];
            }
            else if (str[i] == '1')
            {
                if (i == 0 || (i != 0 && str[i - 1] == '0'))
                    ans += a[i];
            }
        }
        printf("Case #%d: %d\n", ca++, ans);
    }
    return 0;
}

1011

题面

Problem Description
Little sun is an artist. Today he is playing mahjong alone. He suddenly feels that the tree in the yard doesn’t look good. So he wants to decorate the tree.(The tree has n vertexs, indexed from 1 to n.)
Thought for a long time, finally he decides to use the mahjong to decorate the tree.
His mahjong is strange because all of the mahjong tiles had a distinct index.(Little sun has only n mahjong tiles, and the mahjong tiles indexed from 1 to n.)
He put the mahjong tiles on the vertexs of the tree.
As is known to all, little sun is an artist. So he want to decorate the tree as beautiful as possible.
His decoration rules are as follows:

(1)Place exact one mahjong tile on each vertex.
(2)The mahjong tiles’ index must be continues which are placed on the son vertexs of a vertex.
(3)The mahjong tiles’ index must be continues which are placed on the vertexs of any subtrees.

Now he want to know that he can obtain how many different beautiful mahjong tree using these rules, because of the answer can be very large, you need output the answer modulo 1e9 + 7.

Input
The first line of the input is a single integer T, indicates the number of test cases.
For each test case, the first line contains an integers n. (1 <= n <= 100000)
And the next n - 1 lines, each line contains two integers ui and vi, which describes an edge of the tree, and vertex 1 is the root of the tree.

Output
For each test case, output one line. The output format is “Case #x: ans”(without quotes), x is the case number, starting from 1.

Sample Input

2
9
2 1
3 1
4 3
5 3
6 2
7 4
8 7
9 3
8
2 1
3 1
4 3
5 1
6 4
7 5
8 4

Sample Output

Case #1: 32
Case #2: 16

题意

给一棵编号1~n(10^5)的树,然后你可以用1~n的麻将去装饰这棵树,装饰的规则如下:
1.一个父亲节点的每个子节点的编号拿出来排序完了以后要是连续的;
2.每棵子树的每个节点的编号拿出来排序完了以后要是连续的;
3.每个麻将只用一次。
现在问在以上条件下,有多少种装饰这棵树的方法。

解析

先借样例理解一下题意。
如样例2,下图同一框框中的节点都要满足以上3个条件。
这里写图片描述
现在定义,一个父节点下可以有两种节点,一种是leaf(( •̀ ω •́ )y叶子节点),一种是child(有儿子的儿子节点)。
在计算样例的时候发现,在一个父节点下,只能存在至多两个child节点,而leaf节点可以任意个。因为child节点下的子树要满足以上条件2,并且child的兄弟节点要满足以上条件1,所以在这一层当中,一个取当前层连续段的开头,一个取当前层连续段的结尾,而如果出现三个及以上child节点的时候,不可能满足以上条件1,2。
接着就去计算每一个子树的根对总体的贡献,如果当前根下存在child节点,则ans = (2 * ans * fact[leaf]) % mod;
反之,ans = (ans * fact[leaf]) % mod。

然后这题,爆栈一发,不手动扩栈要爆;
mod坑了一发,判断不存在的拜访次数条件一发,最后*2取模一发。。。

代码

#pragma comment(linker, "/STACK:1677721600")
#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 Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

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

const int mod = 1e9 + 7;

int n;
bool vis[maxn];
vector<int> g[maxn];
LL ans;
LL fact[maxn];

bool error;

void factTable()
{
    fact[0] = 1;
    for (int i = 1; i < maxn; i++)
    {
        fact[i] = (fact[i - 1] * i) % mod;
    }
}

void dfs(int rt)
{
    if (error)
        return;
    int sz = g[rt].size();
    int leaf = 0;
    int child = 0;
    for (int i = 0; i < sz; i++)
    {
        int v = g[rt][i];
        if (!vis[v])
        {
            vis[v] = true;
            if (g[v].size() >= 2)
            {
                child++;
                if (child > 2)
                {
                    error = true;
                    return;
                }
                dfs(v);
            }
            else
            {
                leaf++;
            }
        }
    }
    if (child > 2)
    {
        error = true;
        return;
    }
//    cout << "rt:" << rt << " leaf:" << leaf << " chil:" << chil << endl;
    if (child == 0)
        ans = (ans * fact[leaf]) % mod;
    else
        ans = (2 * ans * fact[leaf]) % mod;
}

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
    #endif // LOCAL
    factTable();
    int ncase;
    scanf("%d", &ncase);
    int ca = 1;
    while (ncase--)
    {
        scanf("%d", &n);
        memset(vis, false, sizeof(vis));
        for (int i = 1; i <= n; i++)
        {
            g[i].clear();
        }
        for (int i = 0; i < n - 1; i++)
        {
            int fr, to;
            scanf("%d%d", &fr, &to);
            g[fr].push_back(to);
            g[to].push_back(fr);
        }
        vis[1] = true;
        ans = 1;
        error = false;
        dfs(1);
        if (error)
        {
            printf("Case #%d: 0\n", ca++);
            continue;
        }
        if (n > 1)
            ans <<= 1;
        printf("Case #%d: %lld\n", ca++, ans % mod);
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值