Hdu 2015 Multi-University Training Contest8

1005

题面

Problem Description
Danganronpa is a video game franchise created and developed by Spike Chunsoft, the series’ name is compounded from the Japanese words for “bullet” (dangan) and “refutation” (ronpa).

Now, Stilwell is playing this game. There are n verbal evidences, and Stilwell has m “bullets”. Stilwell will use these bullets to shoot every verbal evidence.

Verbal evidences will be described as some strings Ai, and bullets are some strings Bj. The damage to verbal evidence Ai from the bullet Bj is f(Ai,Bj).
f(A,B)=∑i=1|A|−|B|+1[ A[i…i+|B|−1]=B ]
In other words, f(A,B) is equal to the times that string B appears as a substring in string A.
For example: f(ababa,ab)=2, f(ccccc,cc)=4

Stilwell wants to calculate the total damage of each verbal evidence Ai after shooting all m bullets Bj, in other words is ∑mj=1f(Ai,Bj).

Input
The first line of the input contains a single number T, the number of test cases.
For each test case, the first line contains two integers n, m.
Next n lines, each line contains a string Ai, describing a verbal evidence.
Next m lines, each line contains a string Bj, describing a bullet.

T≤10
For each test case, n,m≤105, 1≤|Ai|,|Bj|≤104, ∑|Ai|≤105, ∑|Bj|≤105
For all test case, ∑|Ai|≤6∗105, ∑|Bj|≤6∗105, Ai and Bj consist of only lowercase English letters

Output
For each test case, output n lines, each line contains a integer describing the total damage of Ai from all m bullets, ∑mj=1f(Ai,Bj).

Sample Input

1
5 6
orz
sto
kirigiri
danganronpa
ooooo
o
kyouko
dangan
ronpa
ooooo
ooooo

Sample Output

1
1
0
3
7

题意

给n(10^5)个模式串,每个串的长度<=10^4。
接着给m(10^5)个匹配串,每个串长度 <= 10^4。
重点:∑|Ai|≤6∗10^5, ∑|Bj|≤6∗10^5。
每个串都由小写字母组成,然后输出n行,每行一个数字,代表所有匹配串B,在模式串Ai中出现的总次数。

解析

比赛的时候就猜这是AC自动机,然后。
被数据量吓到了,又卡了后面那道dp,干脆就没做这题。
结果赛后稍微学了学自动机,发现这题,首先是数据量其实没那么大,其次是这就是一个模板题。
AC自动机详细看上篇:
hdu 2222 AC自动机入门详解
这题其实还没上题难,上题还有单词重复的,这题直接上就行了。

代码

#pragma comment(linker, "/STACK:1677721600")
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <cassert>
#include <iostream>
#include <algorithm>
#define pb push_back
#define mp make_pair
#define LL long long
#define lson lo,mi,rt<<1
#define rson mi+1,hi,rt<<1|1
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a,b) memset(a,b,sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)

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

const int dictSize = 26;

struct Trie
{
    int next[maxn][dictSize];   //next[i][j]保存节点i的那个编号为j的节点(小写字母按字典序编号为0-(a),1-(b),2-(c),...)
    int fail[maxn];             //后缀链接 fail[j]表示节点j沿着失配指针往回走时 遇到的下一个单词节点编号
    int end[maxn];              //保存当前结点结尾的字串个数
    int rt;                     //根
    int nodeNum;                //节点个数

    void init()
    {
        nodeNum = 0;
        rt = newNode();
    }

    int newNode()
    {
        for (int i = 0; i < dictSize; i++)
            next[nodeNum][i] = -1;
        end[nodeNum++] = 0;
        return nodeNum - 1;
    }

    //将字符串str加入Trie前缀树中
    void insert(string str)
    {
        int len = str.length();
        int now = rt;
        for (int i = 0; i < len; i++)
        {
            if (next[now][str[i] - 'a'] == -1)
            {
                next[now][str[i] - 'a'] = newNode();
            }
            now = next[now][str[i] - 'a'];
        }
        end[now]++;
    }

    //建立后缀链接
    void build()
    {
        queue<int> q;
        fail[rt] = rt;
        for (int i = 0; i < dictSize; i++)
        {
            if (next[rt][i] == -1)
            {
                next[rt][i] = rt;
            }
            else
            {
                fail[next[rt][i]] = rt;
                q.push(next[rt][i]);
            }
        }
        while (!q.empty())
        {
            int now = q.front();
            q.pop();
            for (int i = 0; i < dictSize; i++)
            {
                if (next[now][i] == -1)
                {
                    next[now][i] = next[fail[now]][i];
                }
                else
                {
                    fail[next[now][i]] = next[fail[now]][i];
                    q.push(next[now][i]);
                }
            }
        }
    }

    //询问子串们在串str中出现的次数
    int query(string str)
    {
        int len = str.length();
        int now = rt;
        int res = 0;
        for (int i = 0; i < len; i++)
        {
            now = next[now][str[i] - 'a'];
            int temp = now;
            while (temp != rt)
            {
                res += end[temp];
                temp = fail[temp];
            }
        }
        return res;
    }

    void debug()
    {
        for (int i = 0; i < nodeNum; i++)
        {
            printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]);
            for(int j = 0;j < 26;j++)
                printf("%2d",next[i][j]);
            printf("]\n");
        }
    }
} ac;

string str[maxn];
string key;

int main()
{
#ifdef LOCAL
    FIN;
#endif // LOCAL
    int ncase;
    scanf("%d", &ncase);
    while (ncase--)
    {
        int n, m;
        scanf("%d%d", &n, &m);
        for (int i = 0; i < n; i++)
        {
            cin >> str[i];
        }
        ac.init();
        for (int i = 0; i < m; i++)
        {
            cin >> key;
            ac.insert(key);
        }
        ac.build();
        for (int i = 0; i < n; i++)
        {
            printf("%d\n", ac.query(str[i]));
        }
    }
    return 0;
}

1007

题面

SPJ
Problem Description
You have an n∗n matrix.Every grid has a color.Now there are two types of operating:
L x y: for(int i=1;i<=n;i++)color[i][x]=y;
H x y:for(int i=1;i<=n;i++)color[x][i]=y;
Now give you the initial matrix and the goal matrix.There are m operatings.Put in order to arrange operatings,so that the initial matrix will be the goal matrix after doing these operatings

It’s guaranteed that there exists solution.

Input
There are multiple test cases,first line has an integer T
For each case:
First line has two integer n,m
Then n lines,every line has n integers,describe the initial matrix
Then n lines,every line has n integers,describe the goal matrix
Then m lines,every line describe an operating

1≤color[i][j]≤n
T=5
1≤n≤100
1≤m≤500

Output
For each case,print a line include m integers.The i-th integer x show that the rank of x-th operating is i

Sample Input

1
3 5
2 2 1
2 3 3
2 1 3
3 3 3
3 3 3
3 3 3
H 2 3
L 2 2
H 3 3
H 1 3
L 2 3

Sample Output

5 2 4 3 1

题意

给一个n*n(100*100)的矩阵,然后给m(500)个操作。
每个操作是以下两种:
1.H i j 表示将第 i 行所有数染成数字 j 。
2.L i j 表示将第 i 列所有数字染成数字 j。
然后给出原矩阵和染色后的矩阵,求给出一个合理的方案,使得原矩阵可以被染成后矩阵。

解析

看完题竟然觉得是高斯消元,果然脑子蠢,学什么就是什么。
这题也有想过和前一次多校题一样直接模拟,也想过倒回去推。。。
然后,就没有然后了。
这题倒回去推超简单的,遍历每个操作,判断当前这个操作是否满足所有行或者列的颜色都为col,或者已经在之前被染过,如果满足,则使用这个操作。

代码

#pragma comment(linker, "/STACK:1677721600")
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <cassert>
#include <iostream>
#include <algorithm>
#define pb push_back
#define mp make_pair
#define LL long long
#define lson lo,mi,rt<<1
#define rson mi+1,hi,rt<<1|1
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a,b) memset(a,b,sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)

using namespace std;
const int mod = 1e9 + 7;
const double eps = 1e-8;
const double ee = exp(1.0);
const int inf = 0x3f3f3f3f;
const int maxn = 100 + 10;
const double pi = acos(-1.0);
const LL iinf = 0x3f3f3f3f3f3f3f3f;

int readT()
{
    char c;
    int ret = 0,flg = 0;
    while(c = getchar(), (c < '0' || c > '9') && c != '-');
    if(c == '-') flg = 1;
    else ret = c ^ 48;
    while( c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c ^ 48);
    return flg ? - ret : ret;
}

int a[maxn][maxn];
char opt[505][2];
int num[505], col[505];
bool used[505];
vector<int> ans;

int main()
{
#ifdef LOCAL
    FIN;
#endif // LOCAL
    int ncase;
    scanf("%d", &ncase);
    while (ncase--)
    {
        int n, m;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                scanf("%d", &a[i][j]);
            }
        }
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                scanf("%d", &a[i][j]);
            }
        }
        for (int i = 1; i <= m; i++)
        {
            scanf("%s%d%d", opt[i], &num[i], &col[i]);
        }
        mem0(used);
        ans.clear();
        while (ans.size() < m)
        {
            for (int i = 1; i <= m; i++)
            {
                if (!used[i])
                {
                    int k = num[i];
                    if (opt[i][0] == 'L')
                    {
                        bool flag = true;
                        for (int j = 1; j <= n; j++)
                        {
                            if (a[j][k] && a[j][k] != col[i])
                            {
                                flag = false;
                                break;
                            }
                        }
                        if (flag)
                        {
                            ans.pb(i);
                            used[i] = true;
                            for (int j = 1; j <= n; j++)
                            {
                                a[j][k] = 0;
                            }
                        }
                    }
                    else
                    {
                        bool flag = true;
                        for (int j = 1; j <= n; j++)
                        {
                            if (a[k][j] && a[k][j] != col[i])
                            {
                                flag = false;
                                break;
                            }
                        }
                        if (flag)
                        {
                            ans.pb(i);
                            used[i] = true;
                            for (int j = 1; j <= n; j++)
                            {
                                a[k][j] = 0;
                            }
                        }
                    }
                }
            }
        }
        int sz = ans.size();
        for (int i = sz - 1; i > 0; i--)
        {
            printf("%d ", ans[i]);
        }
        printf("%d\n", ans[0]);
    }
    return 0;
}

1008

题面

Problem Description
Give a time.(hh:mm:ss),you should answer the angle between any two of the minute.hour.second hand
Notice that the answer must be not more 180 and not less than 0

Input
There are T(1≤T≤104) test cases
for each case,one line include the time

0≤hh<24,0≤mm<60,0≤ss<60

Output
for each case,output there real number like A/B.(A and B are coprime).if it’s an integer then just print it.describe the angle between hour and minute,hour and second hand,minute and second hand.

Sample Input

4
00:00:00
06:00:00
12:54:55
04:40:00

Sample Output

0 0 0
180 180 0
1391/24 1379/24 1/2
100 140 120
Hint
每行输出数据末尾均应带有空格

题意

给一个时间,输出时与分,时与秒,秒与分 针的夹角。

解析

刷水题的时候遇到题差不多的。
杭电11页那个:
我们知道,时针走30°/小时,分针走6°/分钟。
时针走:30°/h = 0.5°/m = (1/120)°/s
分针走: 6°/m = 0.1°/s
所以在h:m:s时,时针的角度为30*h + m/2 + s/120;
分针的角度为:6*m + s/10;
所以它们的夹角为
fabs(30*h + m/2 + s/120 - 6*m - s/10) = fabs(30*h - 11*m/2 - 11*s/120)
当然,这是在12小时制下(而不是24小时)。
秒针也推下就行了。这题让队友敲的。
一发A,稳稳的。

代码

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <string>
#include <vector>
#include <cstdio>
#include <stack>
#include <queue>
#include <cmath>
#include <list>
#include <map>
#include <set>

#define ULL unsigned long long
#define PI 3.1415926535
#define INF 0x3f3f3f3f
#define LL long long
#define eps 1e-8

using namespace std;

int gcd(int a, int b)
{
    return (b == 0) ? a : gcd(b, a % b);
}


int main()
{
#ifdef LOCAL
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
#endif // LOCAL
    int t;
    int h, m ,s;
    int pos_h, pos_m, pos_s;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d:%d:%d", &h, &m, &s);
        h -= 12;
        h *= 120;
        m *= 120;
        s *= 120;

        pos_h = 30 * h + m / 2 + s / 120;
        pos_m = 6 * m + s / 10;
        pos_s = s * 6;

        int a = abs(pos_h - pos_m), b = abs(pos_h - pos_s), c = abs(pos_m - pos_s);
//            cout << a << " " << b << " " << c << endl;
        a = a % (360 * 120);
        b = b % (360 * 120);
        c = c % (360 * 120);

        if (a > 180 * 120)
            a = 360 * 120 - a;
        if (b > 180 * 120)
             b = 360 * 120 - b;
        if (c > 180 * 120)
             c = 360 * 120 - c;
//            cout << a << " " << b << " " << c << endl;

//        cout << a / 120 << " " <<  b /120<< " " << c /120<<endl;;

        if (a % 120 == 0)
            printf("%d ", a / 120);
        else
        {
            int tmp = gcd(a, 120);
            printf("%d/%d ", a / tmp, 120 / tmp);
        }

        if (b % 120 == 0)
            printf("%d ", b / 120);
        else
        {
            int tmp = gcd(b, 120);
            printf("%d/%d ", b/ tmp, 120 / tmp);
        }

        if (c % 120 == 0)
            printf("%d \n", c / 120);
        else
        {
            int tmp = gcd(c, 120);
            printf("%d/%d \n", c/ tmp, 120 / tmp);
        }
    }
    return 0;
}

1010

题面

Problem Description
Zero Escape, is a visual novel adventure video game directed by Kotaro Uchikoshi (you may hear about ever17?) and developed by Chunsoft.

Stilwell is enjoying the first chapter of this series, and in this chapter digital root is an important factor.

This is the definition of digital root on Wikipedia:
The digital root of a non-negative integer is the single digit value obtained by an iterative process of summing digits, on each iteration using the result from the previous iteration to compute a digit sum. The process continues until a single-digit number is reached.
For example, the digital root of 65536 is 7, because 6+5+5+3+6=25 and 2+5=7.

In the game, every player has a special identifier. Maybe two players have the same identifier, but they are different players. If a group of players want to get into a door numbered X(1≤X≤9), the digital root of their identifier sum must be X.
For example, players {1,2,6} can get into the door 9, but players {2,3,3} can’t.

There is two doors, numbered A and B. Maybe A=B, but they are two different door.
And there is n players, everyone must get into one of these two doors. Some players will get into the door A, and others will get into the door B.
For example:
players are {1,2,6}, A=9, B=1
There is only one way to distribute the players: all players get into the door 9. Because there is no player to get into the door 1, the digital root limit of this door will be ignored.

Given the identifier of every player, please calculate how many kinds of methods are there, mod 258280327.

Input
The first line of the input contains a single number T, the number of test cases.
For each test case, the first line contains three integers n, A and B.
Next line contains n integers idi, describing the identifier of every player.
T≤100, n≤105, ∑n≤106, 1≤A,B,idi≤9

Output
For each test case, output a single integer in a single line, the number of ways that these n players can get into these two doors.

Sample Input

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

Sample Output

1
0
10
60

解析

卡了一个下午,实在什么都不想说了。
有些地方还不明确。
搞懂以后再说吧,A的莫名其妙的。

然后另一段是队友的代码。
稍加分析,我们可以得到满足题意的下所有人的标号和一定等于a,b的和,
那么这样一来求n个数组成a的情况或是组成b的情况值应该是一样的
还有几个地方要特殊考虑,就是全部进a门或全部进b门的情况,这些也是满足条件的。

代码

1:

#pragma comment(linker, "/STACK:1677721600")
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <cassert>
#include <iostream>
#include <algorithm>
#define pb push_back
#define mp make_pair
#define LL long long
#define lson lo,mi,rt<<1
#define rson mi+1,hi,rt<<1|1
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a,b) memset(a,b,sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)

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

int readT()
{
    char c;
    int ret = 0,flg = 0;
    while(c = getchar(), (c < '0' || c > '9') && c != '-');
    if(c == '-') flg = 1;
    else ret = c ^ 48;
    while( c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c ^ 48);
    return flg ? - ret : ret;
}

int dp[maxn][10];
int a[maxn];

int digRt(int x)
{
    if (x % 9 == 0)
        return 9;
    return x % 9;
}

int main()
{
#ifdef LOCAL
    FIN;
#endif // LOCAL
    int ncase;
    scanf("%d", &ncase);
    while (ncase--)
    {
        int n, A, B;
        scanf("%d%d%d", &n, &A, &B);
        int sum = 0;
        for (int i = 1; i <= n; i++)
        {
            a[i] = readT();
            sum += a[i];
        }
        mem0(dp);
        dp[1][a[1]] = 1;
        for (int i = 2; i <= n; i++)
        {
            for (int j = 1; j <= 9; j++)
            {
                dp[i][digRt(j + a[i])] = (dp[i - 1][digRt(j + a[i])] + dp[i - 1][j]) % mod;
            }
        }

//
//        cout << "----------"<<endl;
//
//        for (int i = 2; i <= n; i++)
//        {
//            for (int j = 1; j <= 9; j++)
//            {
                dp[i][digRt(j + a[i])] = (dp[i - 1][digRt(j + a[i])] + dp[i - 1][j]) % mod;
//                cout << dp[i][j] << " ";
//            }
//            cout << endl;
//        }
//        cout << "---------" <<endl;

        sum = digRt(sum);
        if (sum == digRt(A + B))
        {
            cout << (dp[n][A] + dp[n][B]) % mod << endl;
            continue;
        }
        if (sum != A && sum == B)
        {
            cout << dp[n][B] << endl;
            continue;
        }
        if (sum == A && sum != B)
        {
            cout << dp[n][A] << endl;
            continue;
        }
        cout << 0 << endl;
    }
    return 0;
}

2:

#include <cstdio>
#include <cstring>
int num[100005];
int dp[100005][10];

const int mod = 258280327;

int root(int x, int y)
{
    return (x + y - 1) % 9 + 1;
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        memset(dp, 0 ,sizeof(dp));
        int n,a,b;
        int sum = 0;
        scanf("%d %d %d",&n, &a, &b);
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &num[i]);
            //num[i] = root(num[i], 0);
            sum = root(num[i], sum);
            //printf("%d\n", sum);
        }
        dp[0][0] = 1;
        for(int i = 1; i <= n; i++)
        {
            for(int j = 0; j <= 9; j++)
            {
                dp[i][j] += dp[i - 1][j];
                dp[i][root(num[i], j)] += dp[i - 1][j];
                dp[i][j] = dp[i][j] % mod;
                dp[i][root(num[i],j)] = dp[i][root(num[i], j)] % mod;
            }
        }
        int ans = 0;
        if(root(a,b) == sum)
        {
            ans += dp[n][a];
            if(sum == a)
                ans--;
        }
       if(sum == a)
            ans++;
        if(sum == b)xys
            ans++;
        printf("%d\n",ans);
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值