2021-07-03

文章目录

Contest1201 - 搜索,并查集

Problem A

序列

Problem A: 序列Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 122 Solved: 44
[Submit] [Status] [Web Board] [Creator:editor]

Description

给定一个只包含一个数字1的序列 [1]。

现在,要对该序列进行 n - 1次扩充。

每次扩充时,首先要将序列本身添加到其自身的尾部,然后还要在两个序列中间插入还未使用过的最小正整数。

例如,序列 [1] 经过一次扩充后,得到序列 [1,2,1],再经过一次扩充后,得到序列[1,2,1,3,1,2,1]。

现在,请你计算在经过 n−1次扩充后,序列的第 k 个元素的值是多少?(元素从 1 开始编号)

Input

共一行,包含两个整数 n 和 k。
1 ≤ n ≤ 50
1 ≤ k ≤ 2n-1

Output

输出一个整数,表示经过 n−1 次扩充后,序列的第 k 个元素的值。

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
4 6
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
2
HINT

样例解释
对于样例 ,经过 3 次扩充,得到序列 [1,2,1,3,1,2,1,4,1,2,1,3,1,2,1],其第 6 个元素为 2。

题解

121312141213121

其实看一个数要再碰到自己,先重复前面的,再遇到新的数,再遇到前面的。

比如2就会4次之后就再遇见自己

3就会8次之后再遇见3

4是16次之后遇见自己

其实就是前一个中间的个数*2+2化为前面中间遇见的个数+1之后再x2

前面中间的个数一定是奇数+1之后就是偶数所以这样的特性都可以除以2,看他需要几次才能除到奇数

AC代码

#include<iostream>
#include<algorithm>
#include<stack>
#include<deque>
#include<vector>
#include<cmath>
#include<cstdio>
 
#define IOS  ios::sync_with_stdio(false)
#define endl "\n"
using namespace std;
const int N = 1e6 + 10;
int a[N];
 
long long ok(long long k) {
    long long p = 0;
    while (k % 2 == 0) {
        k /= 2;
        p++;
    }
    return p + 1;
}
 
int main() {
//    IOS;
    a[1] = 1;
    long long n, k;
    cin >> n >> k;
    cout << ok(k) << endl;
    return 0;
}
/**************************************************************
    Problem: 3152
    User: 20320220114
    Language: C++
    Result: Accepted
    Time:0 ms
    Memory:5992 kb
****************************************************************/

Problem B

结束

Problem B: 结束Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 51 Solved: 42
[Submit] [Status] [Web Board] [Creator:editor]

Description

有n个孩子,每个孩子都在读一本独特的书。在任何一天结束时,第i个孩子将把他的书交给第pi个孩子(如果i = pi,则该孩子将把他的书交给他自己)。保证pi的所有值都是从1到n的不同整数(即p是一个排列)。序列p每天都不变化,它是固定的。
例如,如果n = 6且p = [4,6,1,3,5,2],则在第一天结束时,第一个孩子的书将属于第四个孩子,第二个孩子-第二个孩子将属于第六个孩子,依此类推。在第二天结束时,第一个孩子的书将属于第三个孩子,第二个孩子将属于第二个孩子,依此类推。
您的任务是确定从1到n的每个i,第i个孩子的书第一次返还给他的天数。
考虑以下示例:p = [5,1,2,4,3]。第一个孩子的书将传递给以下孩子:
第一天之后,它将属于第五个孩子, 第2天之后,它将属于第3个孩子, 第三天之后,它将属于第二个孩子, 在第4天之后,它将属于第一个孩子。 因此,第四天之后,第一个孩子的书将归还其所有者。第四天的书将在整整一天后第一次归还给他。
您必须回答q个独立查询。

Input

输入的第一行包含一个整数q(1≤q≤200)-查询数。然后q查询。
查询的第一行包含一个整数n(1≤n≤200)-查询中孩子的数量。查询的第二行包含n个整数p1,p2,…,pn(1≤pi≤n,所有pi都是唯一的,即p是排列),其中pi是将得到第i个书的孩子

Output

对于每个查询,在其上打印答案:n个整数a1,a2,…,an,其中ai是该查询中第i个孩子的书第一次还给他的天数。

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
6
5
1 2 3 4 5
3
2 3 1
6
4 6 2 1 5 3
1
1
4
3 4 1 2
5
5 1 2 4 3
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
1 1 1 1 1 
3 3 3 
2 3 3 2 1 3 
1 
2 2 2 2 
4 4 4 1 4

题解

直接暴力模拟就可以了

AC代码

#include<iostream>
#include<algorithm>
#include<stack>
#include<deque>
#include<vector>
#include<cmath>
#include<cstdio>
#include <cstring>
 
#define IOS  ios::sync_with_stdio(false)
#define endl "\n"
using namespace std;
const int N = 1e3 + 10;
int p[N];
int c[N];
 
void dfs(int i, int k, int w) {
    if (k == i) {
        c[i] = w;
        return;
    }
    if (!c[i]) {
        dfs(p[i], k, w + 1);
        c[i] = c[p[i]];
    } else c[i] = c[p[i]] + 1;
 
}
 
int main() {
    IOS;
    int q;
    cin >> q;
    while (q--) {
        memset(c, 0, sizeof c);
        int n;
        cin >> n;
        for (int i = 1; i <= n; i++)
            cin >> p[i];
        for (int i = 1; i <= n; i++) {
            if (!c[i]) {
                dfs(p[i], i, 1);
                c[i] = c[p[i]];
            }
        }
        for (int i = 1; i <= n; i++)
            cout << c[i] << " ";
        cout << endl;
    }
    return 0;
}
/**************************************************************
    Problem: 3153
    User: 20320220114
    Language: C++
    Result: Accepted
    Time:12 ms
    Memory:2248 kb
****************************************************************/

Problem C

357

Problem C: 357Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 128 Solved: 45
[Submit] [Status] [Web Board] [Creator:editor]

Description

现在有一个数,你需要去找不超过他而且只有3,5,7三个数字组成的数的数量。

Input

输入一个整数n
1 ≤ n ≤ 1e9

Output

输出一个数表示能找到这样的数的数量

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
3600
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
13
HINT

这13个数分别为:357 375 537 573 735 753 3357 3375 3537 3557 3573 3575 3577

题解

DFS暴力模拟这些数,位数少的,直接存,一样的就比较一下

AC代码

#include<iostream>#include<algorithm>#include<stack>#include<deque>#include<vector>#include<cmath>#include<cstdio>#include <cstring> #define IOS  ios::sync_with_stdio(false)#define endl "\n"using namespace std;const int N = 1e3 + 10;string s;char qq[3] = {'3', '5', '7'};long long ans;string str; bool check() {    bool p1 = false, p2 = false, p3 = false;    for (char i:str) {        if (i == '3')            p1 = true;        else if (i == '5')            p2 = true;        else if (i == '7')            p3 = true;    }    return p1 && p2 && p3;} void dfs(int p) {    if (p > s.size()) {        return;    }    string q = str;    for (char i : qq) {        str += i;        if ((p < s.size() || p >= s.size() && str <= s) && check())            ans++;        dfs(p + 1);        str = q;    } } int main() {    IOS;    long long n;    ans = 0;    cin >> n;    s = to_string(n);    dfs(1);    cout << ans << endl;    return 0;}/**************************************************************    Problem: 3154    User: 20320220114    Language: C++    Result: Accepted    Time:8 ms    Memory:2244 kb****************************************************************/

Problem D

暴力

Problem D: 暴力Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 87 Solved: 12
[Submit] [Status] [Web Board] [Creator:editor]

Description

给你三个整数N,M,Q,和Q个要求ai,bi,ci,di。
构造一个N项的数列A,序列A里面的值都为正整数,满足 Ai ≤ Ai+1 ,最大项AN不超过M,若满足式子Abi - Aai = ci ,则可获得di 点分,求满足条件的序列的最大得分。

Input

第一行输入N,M,Q,下面Q行,每行4个数。
ai bi ci di
……
aQ bQ cQ dQ

2 ≤ N ≤ 10
1 ≤ M ≤ 10
1 ≤ Q ≤ 50
1 ≤ ai < bi ≤ N ( i = 1,2,…,Q )
0 ≤ ci ≤ M - 1 ( i = 1,2,…,Q )
1 ≤ di ≤ 105 ( i = 1,2,…,Q )
(ai,bi,ci ) ≠ ( aj,bj,cj ) ( i ≠ j)

Output

最大得分

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
3 4 31 3 3 1001 2 2 102 3 2 10
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
110
HINT

这个序列可以为:1 2 4 或 1 3 4

题解

一开始想复杂了,直接把这个序列暴力出来就可以了,拿进去判断一下,取出最大值就可以了

AC代码

// #define LOCAL #include<iostream>#include<algorithm>#include<stack>#include<queue>#include<vector>#include<cmath>#include<unordered_map> #define M 1000000000000000007#define IOS  ios::sync_with_stdio(false)#define endl "\n"using namespace std;const int N = 2e5 + 10;struct no {    int a;    int b;    int c;    int d;} p[N];int w[N];int n, m, q;int ans = 0; void dfs(int k, int e) {    if (k > n) {        int sum = 0;        for (int i = 1; i <= q; i++) {            if (w[p[i].b] - w[p[i].a] == p[i].c)                sum += p[i].d;        }        ans = max(ans, sum);        return;    }    for (int i = e; i <= m; i++) {        w[k] = i;        dfs(k + 1, i);    }} int main() {#ifdef LOCAL    freopen("D:\\CPP\\input.in", "r", stdin);#endif    IOS;    cin >> n >> m >> q;    for (int i = 1; i <= q; i++)        cin >> p[i].a >> p[i].b >> p[i].c >> p[i].d;    dfs(1, 1);    cout << ans << endl;    return 0;}/**************************************************************    Problem: 3155    User: 20320220114    Language: C++    Result: Accepted    Time:73 ms    Memory:6148 kb****************************************************************/

Problem E

安全

Problem E: 安全Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 74 Solved: 5
[Submit] [Status] [Web Board] [Creator:editor]

Description

有一个简单的无向图,由N个顶点和M条边组成。最初,所有顶点都涂上颜色0。第i条边双向连接两个顶点ai和bi。每条边的长度为1。
现在在这个图上执行Q次操作。每次操作有三个数ui,vi,wi,表示所有点到点ui的距离不超过vi的都染上wi。
在Q次操作后找到每个顶点的颜色。

Input

第一行输入N和M,表示N个顶点和M条边。
接下来M行每行两个数ai,bi,表示ai,bi两个顶点相连。
M+1行输入Q,表示执行的操作次数。
接下来Q行每行三个数ui,vi,wi 。
1 ≤ N,M,Q ≤ 105
1 ≤ ai,bi,ui ≤ N
ai ≠ bi
0 ≤ vi ≤ 10
1 ≤ wi ≤ 105

Output

在第i行中,打印Q操作后顶点i的颜色。

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
7 71 21 31 44 55 65 72 326 1 11 2 2
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
2222210

题解

倒着跑这个东西,因为最后这个玩意染色之后,就没有能改变的了,需要剪枝,就是记录当时之前这个点还能跑多远,要是上面的点跑到这,比它小或等于,根本就不需要再去跑了。

AC代码

// #define LOCAL #include<iostream>#include<algorithm>#include<stack>#include<queue>#include<vector>#include<cmath>#include<unordered_map> #define M 1000000000000000007#define IOS  ios::sync_with_stdio(false)#define endl "\n"using namespace std;const int N = 1e5 + 10;vector<int> po[N];int p[N];int vis[N];struct no {    int a;    int b;};struct nono {    int a;    int b;    int c;} qq[N]; void bfs(int a, int b, int c) {    queue<no> num;    if (vis[a] < b) {//        cout << "###" << endl;//        cout << vis[a] << endl;//        cout << a << endl;//        cout << endl;        num.push({a, b});        if (!p[a])            p[a] = c;        vis[a] = b;    }    while (!num.empty()) {        a = num.front().a;        b = num.front().b;        num.pop();        if (b == 1)            return;        for (int i:po[a]) {            if (vis[i] < b - 1) {                if (!p[i])                    p[i] = c;                vis[i] = b - 1;                num.push({i, b - 1});            }        }    }}  int main() {#ifdef LOCAL    freopen("D:\\CPP\\input.in", "r", stdin);#endif    IOS;    int n, m;    cin >> n >> m;    while (m--) {        int a, b;        cin >> a >> b;        po[a].push_back(b);        po[b].push_back(a);    }    int q;    cin >> q;    for (int i = 1; i <= q; i++)        cin >> qq[i].a >> qq[i].b >> qq[i].c;    for (int i = q; i >= 1; i--)        bfs(qq[i].a, qq[i].b + 1, qq[i].c);    for (int i = 1; i <= n; i++)        cout << p[i] << endl;    return 0;}/**************************************************************    Problem: 3156    User: 20320220114    Language: C++    Result: Accepted    Time:618 ms    Memory:11036 kb****************************************************************/

Problem F

深刻

Problem F: 深刻Time Limit: 1 Sec Memory Limit: 256 MB
Submit: 220 Solved: 30
[Submit] [Status] [Web Board] [Creator:editor]

Description

有一个N * N的01矩阵。
'0’代表陆地,'1’代表墙,起点终点一定是陆地。
现在可以在陆地上建传送装置,装置只能建造一次,花费为两点间横坐标/纵坐标的差的平方和,(X1 - X2)2 + (Y1 - Y2)2。
问起点到终点的最小花费。

Input

第一行一个正整数N。
第二行输入起点S1 , T1 。
第二行输入终点S2 , T2 。
下面是N * N的01矩阵。
1 ≤ N ≤ 100
1 ≤ S1 , S2 ≤ N
1 ≤ T1 , T2 ≤ N

Output

输出最小花费。

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
51 15 50000111111001110011000110
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
10

题解

把起点和终点能走的路存下来,直接跑暴力算出最小的。

AC代码

#include<iostream>#include<algorithm>#include<stack>#include<queue>#include<vector>#include<cmath> #define M 1000000000000000007#define IOS  ios::sync_with_stdio(false)#define endl "\n"using namespace std;const int N = 1e6 + 10;struct no {    int x;    int y;};char mm[105][105];int cp[105][105];int n;vector<no> qd, zd;int qu[4][2] = {{1,  0},                {-1, 0},                {0,  1},                {0,  -1}};int qx, qy, zx, zy; bool check(int x, int y) {    return x >= 1 && x <= n && y >= 1 && y <= n && mm[x][y] == '0' && !cp[x][y];} vector<no> bfs(int x, int y) {    queue<no> p;    vector<no> qq;    p.push({x, y});    qq.push_back({x, y});    cp[x][y] = 1;    while (!p.empty()) {        x = p.front().x;        y = p.front().y;        p.pop();        for (auto &i : qu) {            int xx = x + i[0];            int yy = y + i[1];            if (check(xx, yy)) {                p.push({xx, yy});                cp[xx][yy] = 1;                qq.push_back({xx, yy});            }        }    }    return qq;} int ch(no aa, no bb) {    return (aa.x - bb.x) * (aa.x - bb.x) + (aa.y - bb.y) * (aa.y - bb.y);} int main() {//    IOS;    scanf("%d", &n);    scanf("%d%d", &qx, &qy);    scanf("%d%d", &zx, &zy);//    cin >> n >> qx >> qy >> zx >> zy;    for (int i = 1; i <= n; i++)        scanf("%s", &mm[i][1]);//    cout << 1 << endl;    qd = bfs(qx, qy);    zd = bfs(zx, zy);    int ans = -1;    for (auto &i : qd)        for (auto &j : zd)            ans = (ans == -1) ? ch(i, j) : min(ans, ch(i, j));    printf("%d\n", ans);    return 0;}/**************************************************************    Problem: 3163    User: 20320220114    Language: C++    Result: Accepted    Time:519 ms    Memory:2292 kb****************************************************************/

Problem G

DFS初练

Problem G: DFS初练Time Limit: 1 Sec Memory Limit: 512 MB
Submit: 633 Solved: 271
[Submit] [Status] [Web Board] [Creator:Imported]

Description

作为DFS的基础题,我们要求对于1~N按字典序输出所有的排列情况。

Input

N(1 <= N <= 9)
注:测试数据包含多组

Output

输出对应的字典序全排列,数之间以空格隔开,每个排列最后一个数后换行。
每个数据处理完后空一行

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
23
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
1 22 11 2 31 3 22 1 32 3 13 1 23 2 1

题解

直接dfs记录前面跑过的,跑过的就不跑了

AC代码

#include<stdio.h>int a[10];void dfs(int x,int n){    if(x>n)    {        for(int i=1;i<=n;i++)            printf("%d ",a[i]);        printf("\n");        return ;    }    else{        for (int i = 1; i <= n; i++) {            int o = 1;            for (int j = 1; j < x; j++) {                if (a[j] == i)                    o = 0;            }            if (o == 1) {                a[x] = i;                dfs(x + 1, n);            }        }    }}int main(){    int n;    while(~scanf("%d",&n)) {        dfs(1, n);        printf("\n");    }}/**************************************************************    Problem: 2144    User: 20320220114    Language: C    Result: Accepted    Time:972 ms    Memory:1156 kb****************************************************************/

Problem H

Oil Deposits

Problem H: Oil DepositsTime Limit: 1 Sec Memory Limit: 512 MB
Submit: 533 Solved: 318
[Submit] [Status] [Web Board] [Creator:Imported]

Description

The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSurvComp works with one large rectangular region of land at a time, and creates a grid that divides the land into numerous square plots. It then analyzes each plot separately, using sensing equipment to determine whether or not the plot contains oil. A plot containing oil is called a pocket. If two pockets are adjacent, then they are part of the same oil deposit. Oil deposits can be quite large and may contain numerous pockets. Your job is to determine how many different oil deposits are contained in a grid.

Input

The input contains one or more grids. Each grid begins with a line containing m and n, the number of rows and columns in the grid, separated by a single space. If m = 0 it signals the end of the input; otherwise 1 <= m <= 100 and 1 <= n <= 100. Following this are m lines of n characters each (not counting the end-of-line characters). Each character corresponds to one plot, and is either *', representing the absence of oil, or@’, representing an oil pocket.

Output

are adjacent horizontally, vertically, or diagonally. An oil deposit will not contain more than 100 pockets.

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
1 1*3 5*@*@***@***@*@*1 8@@****@*5 5 ****@*@@*@*@**@@@@*@@@**@0 0
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
0122

题解

可以用dfs跑完一堆的,也可以用并查集把一堆的全部指向根,就代表他们是一块的

AC代码

#include<stdio.h>char a[105][105];void so(int y, int x){    if (a[y][x] == '@') a[y][x] = '*';    {        if (a[y - 1][x] == '@') so(y - 1, x);        if (a[y - 1][x - 1] == '@') so(y - 1, x - 1);        if (a[y - 1][x + 1] == '@') so(y - 1, x + 1);        if (a[y][x - 1]=='@') so(y, x - 1);        if (a[y][x + 1]=='@') so(y, x + 1);        if (a[y + 1][x] == '@') so(y + 1, x);        if (a[y + 1][x - 1] == '@') so(y + 1, x - 1);        if (a[y + 1][x + 1] == '@') so(y + 1, x + 1);    }}int main(){    int n;    int m;    int i, j, k;    while (scanf("%d%d", &n, &m) && m)    {        k = 0;        for (i = 1; i <= n; i++)        {            scanf("%s", &a[i][1]);        }        for (i = 1; i <= n; i++)        {            for (j = 1; j <= m; j++)            {                if (a[i][j] == '@')                {                    so(i, j);                    k++;                }            }        }        printf("%d\n", k);    }    return 0;}/**************************************************************    Problem: 2074    User: 20320220114    Language: C++    Result: Accepted    Time:5 ms    Memory:1168 kb****************************************************************/

Problem I

代码放哪儿

Problem I: 代码放哪儿Time Limit: 1 Sec Memory Limit: 32 MB
Submit: 389 Solved: 153
[Submit] [Status] [Web Board] [Creator:Imported]

Description

奥利奥有个梦想,想在大地上放满他的代码,这些代码都长得一样,他想用n个代码占领n*n的土地,即任意2个代码不允许处在同一排,同一列,也不允许处在与土地边框成45角的斜线上,奥利奥最近老眼昏花,想让你帮他算算有多少种合法的放置方案。

Input

输入为多组输入,数据组数小于100000。
每组数据为一个正整数N≤10,表示土地为n*n和代码的数量;如果N=0,表示结束。

Output

每行一个正整数,表示对应输入行的代码的不同放置数量

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
1850
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
19210

题解

用DFS去遍历每一排,要是可以就加一

AC代码

#include<iostream>#include<cstring>int map[15][15];int s[15];int ce(int n,int m,int t){    int i;    for(i=1;i<=t;i++){        if(map[i][m]==1){            return 0;        }        if(map[n][i]==1){            return 0;        }        if(n+i<=t&&m+i<=t&&map[n+i][m+i]==1){            return 0;        }        if(n-i>=1&&m-i>=1&&map[n-i][m-i]==1){            return 0;        }        if(n+i<=t&&m-i>=1&&map[n+i][m-i]==1){            return 0;        }        if(n-i>=1&&m+i<=t&&map[n-i][m+i]==1){            return 0;        }    }    return 1;}void dfs(int n,int m){    int i,j,h;    if(n>m){        s[m]++;//        for(i=1;i<=m;i++){//            for(j=1;j<=m;j++){//                printf("%d ",map[i][j]);//            }//            printf("\n");//        }//        printf("\n");        return ;    }//    if(m%2!=0)//        h=m/2+1;//    else h=m/2;    for(i=1;i<=m;i++){//        if(n!=1||i<=h) {            if (ce(n, i, m)) {                map[n][i] = 1;                dfs(n + 1, m);                map[n][i] = 0;            }//        }    }}int main(){    int n,m,i;    for(i=1;i<=10;i++) {        memset(map, 0, sizeof(map));        dfs(1, i);    }//    if(s>0&&n>1) {//        if (n % 2 != 0)//            m = 1;//        else m = 0;//    }//    else m=0;    while(~scanf("%d",&n)&&n){        printf("%d\n",s[n]);    }}/**************************************************************    Problem: 2711    User: 20320220114    Language: C++    Result: Accepted    Time:83 ms    Memory:2088 kb****************************************************************/

Problem J

传送

Problem J: 传送Time Limit: 2 Sec Memory Limit: 128 MB
Submit: 342 Solved: 36
[Submit] [Status] [Web Board] [Creator:editor]

Description

N * M的矩阵中起点’S’,终点’G’,有26种传送门’a’……‘z’,障碍物’#’,平地’.’。
1秒钟可以上,下,左,右移动,如果身处某一种传送门,可以选择用1秒钟传送到任意同种传送门。
问从起点到终点最短用时,如果永远到不了输出-1。

Input

第一行两个整数N,M。
接下来为N * M的矩阵图。
1 ≤ N,M ≤ 2000

Output

输出从S到G的最短时间。
如果从初始位置无法到达目的地,则输出-1。

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
9 10.#...p..####..y.p..###..#....w...Gz.....v..#.mg...#.....#f.c...........#...S......##v..##.
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
6

题解

BFS跑到az的时候,就把下面能跑的路全部放进队列,因为传送也要一秒,跟走周围一样的,不过要记录跑过的字母,让他不再传送第二次,同一字母的传送门传送第二次没有意义

AC代码

#include<iostream>#include<algorithm>#include<stack>#include<queue>#include<vector>#include<cmath> #define M 1000000000000000007#define IOS  ios::sync_with_stdio(false)#define endl "\n"using namespace std;const int N = 1e6 + 10;struct no {    int y;    int x;};char cc[2005][2005];int qq[2005][2005];int a[30];//int pp[2005][2005];vector<no> ch[30];int n, m;int qu[4][2] = {{1,  0},                {-1, 0},                {0,  1},                {0,  -1}}; bool check(int y, int x) {    return y >= 1 && y <= n && x >= 1 && x <= m && cc[y][x] != '#' && !qq[y][x];} int bfs(int yy, int xx) {    queue<no> q;//    queue<no> z;//    z.push(yyy, xxx);    q.push({yy, xx});    qq[yy][xx] = 1;    while (!q.empty()) {        yy = q.front().y;        xx = q.front().x;        q.pop();        if (cc[yy][xx] >= 'a' && cc[yy][xx] <= 'z' && !a[cc[yy][xx] - 'a']) {            a[cc[yy][xx] - 'a']++;            for (no i: ch[cc[yy][xx] - 'a']) {                if (check(i.y, i.x)) {                    q.push(i);                    qq[i.y][i.x] = qq[yy][xx] + 1;                }            }        }        for (auto &i : qu) {            int y = yy + i[0];            int x = xx + i[1];            if (check(y, x)) {                qq[y][x] = qq[yy][xx] + 1;                if (cc[y][x] == 'G')                    return qq[y][x] - 1;                q.push({y, x});            }        }    }    return -1;} int main() {//    IOS;    scanf("%d%d", &n, &m);    int yy, xx;    for (int i = 1; i <= n; i++)        scanf("%s", &cc[i][1]);    for (int i = 1; i <= n; i++) {        for (int j = 1; j <= m; j++) {            if (cc[i][j] == 'S') {                yy = i;                xx = j;            } else if (cc[i][j] >= 'a' && cc[i][j] <= 'z') {                ch[cc[i][j] - 'a'].push_back({i, j});            }        }    }    cout << bfs(yy, xx) << endl;    return 0;}/**************************************************************    Problem: 3157    User: 20320220114    Language: C++    Result: Accepted    Time:862 ms    Memory:26460 kb****************************************************************/

Problem K

魔法

Problem K: 魔法Time Limit: 2 Sec Memory Limit: 128 MB
Submit: 186 Solved: 21
[Submit] [Status] [Web Board] [Creator:editor]

Description

给你一个N*M的矩阵,’#‘表示墙,’.'表示道路。
有一个魔术师在(sx , sy),他需要到达(tx , ty)。
他可以向相邻的道路垂直或水平移动一步。
也可以使用他的魔法将自己扭曲传送到5×5区域的一个道路,该区域以他当前所在的位置为中心。
求魔术师到达(tx , ty)需要的最少使用魔法次数。

Input

第一行输入两个整数N,M。
第二行输入起始位置坐标(sx , sy)。
第三行输入终点位置坐标(tx , ty)。
接下来是N*M的字符矩阵。
1 ≤ N,M ≤ 103
1 ≤ sx ,tx ≤ N
1 ≤ sy ,ty ≤ M

Output

求魔术师到目标点使用魔法的最少次数,如果到不了目标点输出-1。

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
4 41 14 4..#...#..#...#..
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
1

题解

走路不花费,先走完所有能走的,然后走的这些点,全部存入队列,然后使用魔法走,魔法走的所有没走过的路也存起来,再用走路,这样的话,只要找到了终点,就可以直接输出答案。

AC代码

#include<iostream>#include<algorithm>#include<stack>#include<queue>#include<vector>#include<cmath> #define M 1000000000000000007#define IOS  ios::sync_with_stdio(false)#define endl "\n"using namespace std;const int N = 1e6 + 10; struct no {    int x;    int y;    int s; //    bool operator<(const no &a) const {//        return s > a.s;//    }}; int n, m;int x, y, xx, yy;char cc[1005][1005];int qq[1005][1005];int vis[1005][1005];int qu[4][2] = {{1,  0},                {-1, 0},                {0,  1},                {0,  -1}}; bool check(int a, int b) {    return a >= 1 && a <= n && b >= 1 && b <= m && cc[a][b] != '#' && !vis[a][b];} int bfs(int a, int b) {    queue<no> q, p;    q.push({a, b, 1});    p.push({a, b, 1});    vis[a][b] = 1;    while (!q.empty()) {        while (!q.empty()) {            a = q.front().x;            b = q.front().y;            int c = q.front().s;            q.pop();            for (auto &i : qu) {                int aa = a + i[0];                int bb = b + i[1];                if (check(aa, bb)) {                    if (aa == xx && bb == yy)                        return c - 1;                    vis[aa][bb] = c;                    q.push({aa, bb, c});                    p.push({aa, bb, c});                }            }        }        while (!p.empty()) {//            cout << p.size() << endl;            a = p.front().x;            b = p.front().y;            int c = p.front().s;            p.pop();            for (int i = -2; i <= 2; i++) {                for (int j = -2; j <= 2; j++) {                    int aa = a + i;                    int bb = b + j;                    if (check(aa, bb)) {                        if (aa == xx && bb == yy)                            return c;                        vis[aa][bb] = c + 1;                        q.push({aa, bb, c + 1});                    }                }            }        }        p = q;    }    return vis[xx][yy] - 1;} int main() {//    IOS;//    freopen("D:\\CPP\\input.in", "r", stdin);    scanf("%d%d%d%d%d%d", &n, &m, &x, &y, &xx, &yy);    for (int i = 1; i <= n; i++)        scanf("%s", &cc[i][1]);    printf("%d\n", bfs(x, y));    return 0;}/**************************************************************    Problem: 3158    User: 20320220114    Language: C++    Result: Accepted    Time:386 ms    Memory:11128 kb****************************************************************/

Problem L

游戏

Problem L: 游戏Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 212 Solved: 16
[Submit] [Status] [Web Board] [Creator:editor]

Description

给你一个N*M的矩阵,’@‘表示墙,’.'表示道路。
有一个人在(sx , sy),他需要到达(tx , ty)。
他每次可以垂直或水平移动1~K步。
问他到达终点需要几次移动。

Input

第一行输入三个个整数N,M,K。
第二行分别输入起始位置坐标(sx , sy)和终点位置坐标(tx , ty)。
接下来是N*M的字符矩阵。
1 ≤ N,M,K ≤ 106
N * M ≤ 106
1 ≤ sx ,tx ≤ N
1 ≤ sy ,ty ≤ M
sx ≠ tx or sy ≠ ty

Output

输出到达终点的移动次数,如果不能到达输出-1。

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
3 5 23 2 3 4...@..@.....@..
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
6

题解

BFS走的路,但是可以穿过以前走的路,但是如果以前走的路,不是现在走去应该的步数,就没必要穿过了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-izpO7zXk-1625271795819)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20210702200222990.png)]

如果上面的第一步走了,下面的第一步也走了,上面的第二步走了,下面的第二步应该穿过,不然就会大1步,而且因为BFS不可能在有1的同时出现第3步,所以只需要判断走的这一部是不是应该等于本来走过的那一步。

AC代码

//#define LOCAL #include<iostream>#include<queue>#include<cstring> #define IOS  ios::sync_with_stdio(false)using namespace std;int n, m, k;int y1, x1, y2, x2;vector<vector<char> > map;//char map[1005][1005];//int der[1005][1005];vector<vector<int> > der;int lu[4][2] = {{0,  1},                {1,  0},                {0,  -1},                {-1, 0}};struct no {    int y;    int x;};queue<no> q; int bfs(int y, int x, int yy, int xx) {    no bb, aa;    int i, j;    q.push({y, x});    der[y][x] = 1;    while (!q.empty()) {        aa = q.front();        q.pop();        for (i = 0; i < 4; i++) {            bb.y = aa.y;            bb.x = aa.x;            for (j = 1; j <= k; j++) {                bb.y += lu[i][0];                bb.x += lu[i][1];                if (bb.x <= m && bb.x >= 1 && bb.y <= n && bb.y >= 1 && map[bb.y][bb.x] != '@') {                    if (!der[bb.y][bb.x]) {                        q.push(bb);                        der[bb.y][bb.x] = der[aa.y][aa.x] + 1;                        if (bb.y == yy && bb.x == xx)                            return der[yy][xx] - 1;                     } else if (der[bb.y][bb.x] <= der[aa.y][aa.x])                        break;                } else break;            }//        }    }    return der[yy][xx] - 1;} int main() {#ifdef LOCAL    freopen("D:\\CPP\\input.in", "r", stdin);#endif    IOS;    vector<int> e;    vector<char> p;    cin >> n >> m >> k >> y1 >> x1 >> y2 >> x2;    for (int i = 0; i <= m; i++) {        e.push_back(0);        p.push_back(0);    }    der.push_back(e);    map.push_back(p);    for (int i = 1; i <= n; i++) {        string s;        cin >> s;        vector<char> w;        w.push_back(0);        for (char &j : s)            w.push_back(j);        der.push_back(e);        map.push_back(w);    }    cout << bfs(y1, x1, y2, x2) << endl;//    for (int i = 1; i <= n; i++) {//        for (int j = 1; j <= m; j++) {//            cout << der[i][j];//        }//        cout << endl;//    }    return 0;}/**************************************************************    Problem: 3159    User: 20320220114    Language: C++    Result: Accepted    Time:392 ms    Memory:19824 kb****************************************************************/

Problem M

矩阵

Problem M: 矩阵Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 290 Solved: 35
[Submit] [Status] [Web Board] [Creator:editor]

Description

有一个N * N的01矩阵,和一个正整数M。
有一个人从起点出发,他如果在0位置上,他只能移动一步到1,如果在1位置上,他只能移动一步到0。
给定起点,问他最多能移动多少个格子(包含起点)。

Input

第一行两个正整数N,M。
下面N行是N*N的01矩阵。
接下来M行询问,每行两个正整数s,t,表示起点。
2 ≤ N ≤ 103
1 ≤ M ≤ 105

Output

输出M行,每行数字表示最多能移动多少个格子。

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
2 201101 12 2
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
44

题解

使用DFS和并查集,把所有的能走的点全部放到一个根里面,存下这个值就行,到时候任意给一个点,也能找到它的根,并且能直接输出个数。

AC代码

#include<iostream>#include<algorithm>#include<stack>#include<queue>#include<vector>#include<cmath> #define M 1000000000000000007#define IOS  ios::sync_with_stdio(false)#define endl "\n"using namespace std;const int N = 1e6 + 10;struct no {    int y;    int x;};char cc[1005][1005];int qq[1005][1005];no p[1005][1005];int n, m;int qu[4][2] = {{1,  0},                {-1, 0},                {0,  1},                {0,  -1}}; bool check(int yy, int xx, int y, int x) {    return yy >= 1 && yy <= n && xx >= 1 && xx <= n && !qq[yy][xx] && cc[yy][xx] != cc[y][x];} void dfs(int y, int x, int aa, int bb) {    for (auto &i : qu) {        int yy = y + i[0];        int xx = x + i[1];        if (check(yy, xx, y, x)) {            qq[yy][xx] = 1;            qq[aa][bb]++;            p[yy][xx] = {aa, bb};            dfs(yy, xx, aa, bb);        }    }}  int main() {//    IOS;    scanf("%d%d", &n, &m);    for (int i = 1; i <= n; i++)        scanf("%s", &cc[i][1]);    for (int i = 1; i <= n; i++) {        for (int j = 1; j <= n; j++) {            if (!qq[i][j]) {                qq[i][j] = 1;                p[i][j] = {i, j};                dfs(i, j, i, j);            }        }    }    while (m--) {        int a, b;        scanf("%d%d", &a, &b);        printf("%d\n", qq[p[a][b].y][p[a][b].x]);    }    return 0;}/**************************************************************    Problem: 3160    User: 20320220114    Language: C++    Result: Accepted    Time:450 ms    Memory:92916 kb****************************************************************/

Problem N

Maze Problem

Problem N: Maze ProblemTime Limit: 1 Sec Memory Limit: 128 MB
Submit: 500 Solved: 225
[Submit] [Status] [Web Board] [Creator:Imported]

Description

Given a maze, find a shortest path from start to goal.

Input

Input consists serveral test cases.
First line of the input contains number of test case T.
For each test case the first line contains two integers N , M ( 1 <= N, M <= 100 ).
Each of the following N lines contain M characters. Each character means a cell of the map.
Here is the definition for chracter.

Constraint:

  • For a character in the map:
    • ‘S’ : start cell
    • ‘E’ : goal cell
    • ‘-’ : empty cell
    • ‘#’ : obstacle cell
  • no two start cell exists.
  • no two goal cell exists.
Output

For each test case print one line containing shortest path. If there exists no path from start to goal, print -1.

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
15 5S-###-----##---E#------##
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
9

题解

BFS找出答案。

AC代码

#include<iostream>#include<queue>#include<cstring>using namespace std;char map[110][110];long long vis[110][110];int u[4][2]={{1,0},{0,1},{-1,0},{0,-1}};struct no{    int y,x;};queue<no> e;int n,m,i,j;//const int INF=0x3f3f3f3f;bool ok(int y,int x){    return x>=1&&x<=m&&y>=1&&y<=n&&(map[y][x]=='-'||map[y][x]=='E')&&vis[y][x]==0;}void clear(queue<no>& q) {    queue<no> empty;    swap(empty, q);}//void print(){//    for(i=1;i<=n;i++){//        for(j=1;j<=m;j++){//            printf("%d ",vis[i][j]);//        }//        printf("\n");//    }//    printf("\n");//}long long dfs(int y,int x) {    int ny,nx;    int g=0;    struct no v;    int l;    e.push(no{y, x});//    printf("*\n");//    print();    while (!e.empty()) {        v = e.front();        e.pop();//        printf("*\n");        for (l = 0; l < 4; l++) {            ny = v.y + u[l][0];            nx = v.x + u[l][1];//            printf("*%d %d %d %d %d %d\n",ny,nx,u[l][0],u[l][1],v.y,v.x);            if (ok(ny, nx)) {                e.push(no{ny, nx});                vis[ny][nx] = vis[v.y][v.x] + 1;//                print();//                printf("*%d %d\n",ny,nx);                if (map[ny][nx] == 'E') {//                    printf("&&\n");                    g=1;                    clear(e);                    break;                }            }        }    }    if(g)    return vis[ny][nx];    else return -1;} int main(){    int t;    scanf("%d",&t);    while(t--){        memset(map, 0, sizeof(map));        memset(vis, 0, sizeof(vis));        clear(e);        scanf("%d%d",&n,&m);        for(i=1;i<=n;i++)            scanf("%s",map[i]+1);        for(i=1;i<=n;i++) {            for (j = 1; j <= m; j++) {                if (map[i][j] == 'S') {                    printf("%lld\n", dfs(i, j));                    break;                }            }        }    }    return 0;}/**************************************************************    Problem: 1777    User: 20320220114    Language: C++    Result: Accepted    Time:0 ms    Memory:2204 kb****************************************************************/

Problem O

Prime Path

Problem O: Prime PathTime Limit: 1 Sec Memory Limit: 128 MB
Submit: 213 Solved: 141
[Submit] [Status] [Web Board] [Creator:Imported]

Description

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rvQ2K2dJ-1625271795822)(http://acm.ccniit.com/JudgeOnline/upload/image/20180425/20180425224207_96545.png)]
The ministers of the cabinet were quite upset by the message from the Chief of Security stating that they would all have to change the four-digit room numbers on their offices.
— It is a matter of security to change such things every now and then, to keep the enemy in the dark.
— But look, I have chosen my number 1033 for good reasons. I am the Prime minister, you know!
— I know, so therefore your new number 8179 is also a prime. You will just have to paste four new digits over the four old ones on your office door.
— No, it’s not that simple. Suppose that I change the first digit to an 8, then the number will read 8033 which is not a prime!
— I see, being the prime minister you cannot stand having a non-prime number on your door even for a few seconds.
— Correct! So I must invent a scheme for going from 1033 to 8179 by a path of prime numbers where only one digit is changed from one prime to the next prime.

Now, the minister of finance, who had been eavesdropping, intervened.
— No unnecessary expenditure, please! I happen to know that the price of a digit is one pound.
— Hmm, in that case I need a computer program to minimize the cost. You don’t know some very cheap software gurus, do you?
— In fact, I do. You see, there is this programming contest going on… Help the prime minister to find the cheapest prime path between any two given four-digit primes! The first digit must be nonzero, of course. Here is a solution in the case above.

1033
1733
3733
3739
3779
8779
8179

The cost of this solution is 6 pounds. Note that the digit 1 which got pasted over in step 2 can not be reused in the last step – a new 1 must be purchased.

Input

One line with a positive number: the number of test cases (at most 100). Then for each test case, one line with two numbers separated by a blank. Both numbers are four-digit primes (without leading zeros).

Output

One line for each case, either with a number stating the minimal cost or containing the word Impossible.

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
31033 81791373 80171033 1033
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
670

题解

用BFS去跑这每个数,然后判断一下是不是可以的,然后直接跑就完事了

AC代码

#include<iostream>#include<queue>#include<cstring>using namespace std;queue<int> q;long long map[10002];int zhi[10002];int ji[5];int ok(int *k){    return k[1]*1000+k[2]*100+k[3]*10+k[4];}void ko(int n){    int i;    for(i=4;n>0;i--){        ji[i]=n%10;        n/=10;    }}void clear(queue<int>& x){    queue<int> m;    swap(m,x);}long long bfs(int n,int m) {    int i, j, h;//    k=m;    q.push(n);     while (!q.empty() && n != m) {        n = q.front();        q.pop();        for (i = 1; i <= 4; i++) {            for (j = 0; j <= 9; j++) {                if (i != 1 || j != 0) {                    ko(n);                    if (ji[i] != j) {                        ji[i] = j;                        h = ok(ji);                        if (map[h] == 0 && zhi[h] == 0) {                            q.push(h);                            map[h] = map[n] + 1;                            if (h == m) {                                clear(q);                                break;                            }                        }                    }                }            }            if (h == m) {                clear(q);                break;            }        }    }    return map[m];}int main(){    int t;    int n,m,i,j;    memset(zhi,0,sizeof zhi);    for(i=2;i<10000;i++){        if(zhi[i]==0) {            for (j = 2 * i; j < 10000; j += i) {                zhi[j] = 1;            }        }    }//    printf("%d %d %d\n",zhi[41],zhi[41*199],41*199);    scanf("%d",&t);    while(t--){        memset(map,0,sizeof map);        scanf("%d%d",&n,&m);//        ko(n);//        printf("%d\n",ok(ji));        printf("%lld\n",bfs(n,m));    }    return 0;}//1733 2 7 1 0 1033//3733 1 3 2 1 1733//8039 1 8 2 1 1039 *//3739 4 9 3 2 3733//8059 3 5 3 2 8039 *//3779 3 7 4 3 3739//8159 2 1 4 3 8059 *//8779 1 8 5 4 3779//8179 3 7 5 4 8159 */**************************************************************    Problem: 1775    User: 20320220114    Language: C++    Result: Accepted    Time:9 ms    Memory:2216 kb****************************************************************/

Problem P

解救zser

Problem P: 解救zserTime Limit: 1 Sec Memory Limit: 128 MB
Submit: 421 Solved: 87
[Submit] [Status] [Web Board] [Creator:16310120805]

Description

zser前不久看了克里斯托弗·诺兰在2010年执导的<盗梦空间>,看完后,他感叹不已,于是每天就想着去入侵别人的梦,在网上找疯狂这方面的博客(哎,中毒太深!!!).功夫不负有心人,zser在豆瓣上终于找到一篇相关的博客,为了验证博客是否有用,zser决定拿飛機飛过天空开刀.
在一个月黑风高的夜晚,zser潜入了飛機飛过天空的寝室,撬开了窗户,开始了实验,按照博客上写的,zser成功进入了飛機飛过天空的梦境,这可把zser高兴坏了,好景不长,他没想到飛機飛过天空的梦境被施加了保护,还好博客中有相应的措施,于是zser喊出"快来救我!",梦境中随机出现了多个解救zser的盟友.
我们可以把梦境看成一个二维的图形,"*“代表不能通过的墙,”+"代表可以行走的路,"Z"代表zser,"P"代表飛機飛过天空梦境中的护卫,"F"代表来解救zser的盟友,求盟友解救zser的最小步数,规定盟友非常强大足以击败所有的护卫,并且走护卫这个点的时间为2(因为解决护卫需要时间),走普通道路时间为1.规定护卫和zser不会动,盟友只能向上,下,左,右.

Input

输入一个T,表示T组数据。T<=100
输入 : 第一行输入两个整数代表n,m(1<=n,m<=200).
紧接着是n行,每行有m个字符.
"Z"代表zser学长,
"*"代表墙,
"+"代表路,
"P"代表守卫,
"F"代表解救zser学长的朋友.

Output

输出 : 输出zser逃出梦境的最小时间,如果zser无法逃出则输出"Infinite loop".

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
17 8*+*****+*+**++F+*++P++P+++PZP*+***+P+*+++*++++++++++++++
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
6

题解

用优先队列,让哪个小的花费先跑。

AC代码

#include<iostream>#include<queue>#include<cstring>using namespace std;struct no{    int y;    int x;    int s;    friend bool operator< (no n1, no n2)    {        return n1.s > n2.s;    }};char map[205][205];int ksr[205][205];int lu[4][2]={{1,0},{0,1},{-1,0},{0,-1}};int n,m,yy,xx;priority_queue<no> q;void clear(priority_queue<no>&k){    priority_queue<no> l;    swap(l,k);}int bfs(){    int i;    no kk,ll;    while(!q.empty()) {        kk=q.top();        q.pop();        for (i = 0; i < 4; i++) {            ll.y=kk.y+lu[i][0];            ll.x=kk.x+lu[i][1];            if(ll.y<=n&&ll.y>=1&&ll.x>=1&&ll.x<=m&&map[ll.y][ll.x]!='*'&&map[ll.y][ll.x]!='F'&&ksr[ll.y][ll.x]==0){                if(map[ll.y][ll.x]=='P') {                    ll.s = kk.s + 2;                }                else{                    ll.s=kk.s+1;                }                ksr[ll.y][ll.x]=ll.s;                if(map[ll.y][ll.x]=='Z')                    return ksr[yy][xx];                q.push(ll);            }        }    }    return ksr[yy][xx];}int main(){    int t,k,j,i;    scanf("%d",&t);    while(t--){        clear(q);        memset(ksr,0,sizeof (ksr));        scanf("%d%d",&n,&m);        for(i=1;i<=n;i++){            scanf("%s",map[i]+1);        }        for(i=1;i<=n;i++){            for(j=1;j<=m;j++){                if(map[i][j]=='F')                    q.push({i,j,0});                if(map[i][j]=='Z'){                    yy=i;                    xx=j;                }            }        }        k=bfs();        if(k)            printf("%d\n",k);        else printf("Infinite loop\n");    }}/**************************************************************    Problem: 2736    User: 20320220114    Language: C++    Result: Accepted    Time:97 ms    Memory:2308 kb****************************************************************/

Problem Q

朋友

Problem Q: 朋友Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 153 Solved: 38
[Submit] [Status] [Web Board] [Creator:editor]

Description

有N个人编号从1 ~ N,M对朋友关系和K对敌对关系。
现在给每个人找候选朋友,候选朋友是他的间接朋友(朋友的朋友),但不能与他是敌对关系。
问每个人有多少个候选朋友。

Input

第一行为三个整数N,M,K。
后面M行,每行两个整数Ai,Bi,表示朋友关系。
接下来K行,每行两个整数Ci,Di,表示敌对关系。
2 ≤ N ≤ 105
0 ≤ M , K ≤ 105
1 ≤ Ai , Bi ≤ N
1 ≤ Ci , Di ≤ N
Ai ≠ Bi , Ci ≠ Di
(Ai , Bi) ≠ (Aj , Bj) (i ≠ j)
(Ai , Bi) ≠ (Bj , Aj)
(Ci , Di) ≠ (Cj , Dj) (i ≠ j)
(Ci , Di) ≠ (Dj , Cj)
(Ai , Bi) ≠ (Cj , Dj)
(Ai , Bi) ≠ (Dj , Cj)

Output

从编号1 ~ N,依次输出他有多少个候选朋友,中间留空格。

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
4 4 12 11 33 23 44 1
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
0 1 0 1

题解

把他的朋友数量记录下来,用并查集把他朋友和朋友的朋友连在一起,然后有可能朋友的朋友是敌人,然后把他在他朋友的朋友中的敌人数量存下来,减去就可以了

AC代码

//#define LOCAL#pragma gcc optimize(3) #include<iostream>#include<queue>#include<cstring> #define IOS  ios::sync_with_stdio(false)using namespace std;const int N = 1e6 + 10;int p[N];int sum[N];int pp[N]; void init(int n) {    for (int i = 1; i <= n; i++) {        p[i] = i;        sum[i]++;    }} int find(int x) {    return p[x] = p[x] == x ? x : find(p[x]);} void book(int x, int y) {    x = find(x);    y = find(y);    if (x != y)        p[x] = y;} int main() {#ifdef LOCAL    freopen("D:\\CPP\\input.in", "r", stdin);#endif    IOS;    int n, m, k;    int a, b;    cin >> n >> m >> k;    init(n);    while (m--) {        cin >> a >> b;        book(a, b);        sum[a]++;        sum[b]++;    }    while (k--) {        cin >> a >> b;        if (find(a) == find(b)) {            sum[a]++;            sum[b]++;        }    }    for (int i = 1; i <= n; i++)        pp[find(i)]++;    for (int i = 1; i <= n; i++)        cout << pp[find(i)] - sum[i] << " ";    cout << endl;    return 0;}/**************************************************************    Problem: 3161    User: 20320220114    Language: C++    Result: Accepted    Time:180 ms    Memory:15080 kb****************************************************************/

Problem R

连接

Problem R: 连接Time Limit: 2 Sec Memory Limit: 128 MB
Submit: 115 Solved: 27
[Submit] [Status] [Web Board] [Creator:editor]

Description

有N个城市,城市之间有K条道路和L条铁路。
问对于每个城市,有多少城市既可以通过道路到达这个城市,也可以通过铁路到达这个城市(自己可以到达自己)。

Input

第一行三个正整数N,K,L,分别表示N个城市,K条道路和L条铁路。
接下来K行,每行两个正整数ai,bi,表示ai城市和bi城市通过道路相连。
接下来L行,每行两个正整数ci,di,表示ci城市和di城市通过铁路相连。
2 ≤ N ≤ 2 * 105
1 ≤ K,L ≤ 105
1 ≤ ai,bi,ci,di ≤ 105
ai < bi,ci < di
(ai , bi) ≠ (aj , bj) (i ≠ j)
(ci , di) ≠ (cj , dj) (i ≠ j)

Output

输出N个整数。其中第i个应代表通过公路和铁路与第i个城市相连的城市数量。

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
4 3 11 22 33 42 3
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
1 2 2 1

题解

用两个并查集分别存下铁路和公路的连通情况,要是有其他的数字跟这个数字也同时处于同样的两个连通块,说明这两个地方是连接的,用map去找到块,加一后,代表两个块多了一个跟他处于同两个块。

AC代码

// #define LOCAL#pragma gcc optimize(3) #include<iostream>#include<queue>#include<cstring>#include <algorithm>#include<map> #define IOS  ios::sync_with_stdio(false)using namespace std;const int N = 1e6 + 10;map<pair<int, int>, int> cp;int p[N];int sum[N];int s[N]; void init(int n) {    for (int i = 1; i <= n; i++) {        s[i] = p[i] = i;        sum[i]++;    }} int find(int x) {    return p[x] = p[x] == x ? x : find(p[x]);} void book(int x, int y) {    x = find(x);    y = find(y);    if (x != y)        p[x] = y;} int findd(int x) {    return s[x] = s[x] == x ? x : findd(s[x]);} void join(int x, int y) {    x = findd(x);    y = findd(y);    if (x != y)        s[x] = y;}  int main() {#ifdef LOCAL    freopen("D:\\CPP\\input.in", "r", stdin);#endif    IOS;    int n, m, k;    int a, b;    cin >> n >> m >> k;    init(n);    while (m--) {        cin >> a >> b;        book(a, b);    }    while (k--) {        cin >> a >> b;        join(a, b);    }    for (int i = 1; i <= n; i++) {//        cout << find(i) << " " << findd(i) << endl;        cp[{find(i), findd(i)}]++;//        cout << cp[{find(i), findd(i)}] << endl;    }    for (int i = 1; i <= n; i++)        cout << cp[{find(i), findd(i)}] << " ";    cout << endl;    return 0;}/**************************************************************    Problem: 3162    User: 20320220114    Language: C++    Result: Accepted    Time:1035 ms    Memory:25460 kb****************************************************************/

Problem S

尽快

Problem S: 尽快Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 70 Solved: 14
[Submit] [Status] [Web Board] [Creator:editor]

Description

有N个点,M条边,现在依次删掉这些边,求每一次删掉后有多少点对不连通。

Input

第一行输入两个正整数N,M。
下面M行,每行两个正整数Ai ,Bi,表示点Ai 和Bi 相连。
2 ≤ N ≤ 105
1 ≤ M ≤ 105
1 ≤ Ai < Bi ≤ N

Output

按顺序1,2,…,M输出。答案可能不符合32-位整数类型。

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
4 51 23 41 32 31 4
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
00456

题解

倒着跑,就是查看连通后,不连通的有多少,最开始先把全部不连通算出来n*(n-1)/2,然后连接两个点后,说明两个块都联通了,这个时候就乘两边的数量,就是连接的个数。

AC代码

// #define LOCAL#pragma gcc optimize(3) #include<iostream>#include<queue>#include<cstring>#include <algorithm>#include<map> #define IOS  ios::sync_with_stdio(false)using namespace std;const int N = 1e5 + 10;long long p[N];long long ans[N];long long sum[N];long long h[N][2]; void init(int n) {    for (int i = 1; i <= n; i++) {        p[i] = i;        sum[i] = 1;    }} long long findd(long long x) {    return p[x] = p[x] == x ? x : findd(p[x]);} void book(long long x, long long y) {    x = findd(x);    y = findd(y);    if (x != y) {        p[x] = y;        sum[y] += sum[x];    }}  int main() {#ifdef LOCAL    freopen("D:\\CPP\\input.in", "r", stdin);#endif    IOS;    int n, m;    cin >> n >> m;    long long k =1ll* n * (n - 1) / 2;    init(n);    for (int i = 0; i < m; i++)        cin >> h[i][0] >> h[i][1];    h[m][0] = h[m][1] = 0;    for (int i = m; i >= 1; i--) {        if (findd(h[i][0]) != findd(h[i][1]))            k -= sum[findd(h[i][0])] * sum[findd(h[i][1])];        book(h[i][0], h[i][1]);        ans[i] = k;    }    for (int i = 1; i <= m; i++)        cout << ans[i] << "\n";    return 0;}/**************************************************************    Problem: 3164    User: 20320220114    Language: C++    Result: Accepted    Time:121 ms    Memory:6728 kb****************************************************************/

Problem T

肯定

Problem T: 肯定Time Limit: 5 Sec Memory Limit: 128 MB
Submit: 89 Solved: 11
[Submit] [Status] [Web Board] [Creator:editor]

Description

有N个学生去学校,第i个学生在班级Bi 。
某个学生在去上学的路上可能会遇到其他的学生并加入到该集合。
您将得到Q查询,应该按顺序处理。有两种类型的查询,其格式如下所示:
1 a b:包含学生a的集合和包含学生b的集合合并。
2 x y:要求您查找在本次查询时属于y班且与学生x(包括学生x)已在同一组中的学生人数。

Input

第一行两个正整数N,Q。
第二行N个正整数,表示第i个学生在班级Bi 。
下面Q行,每行三个正整数,第一个正整数表示查询的类型,后两个正整数表示a,b或x,y。
1 ≤ N,Q ≤ 2 * 105
1 ≤ Bi ,a,b,x,y ≤ N
a ≠ b

Output

如果是查询类型2,将查询的答案按格式依次打印在各自的行中。

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
5 51 2 3 2 11 1 21 2 52 1 11 3 42 3 4
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
20
HINT

在第三次查询时,学生1已经加入了学生2和5。在这三个学生中,有两个属于1班。

在第五次查询时,学生3已经加入了学生4,在这两个学生中,没有一个属于4班。

题解

直接跑的时候,存下这个块的信息,然后合并的时候,跑信息较少的那个块赋值给另一个,因为这样跑的少一些。

AC代码

// #define LOCAL #include<iostream>#include<algorithm>#include<stack>#include<queue>#include<vector>#include<cmath>#include<unordered_map> #define M 1000000000000000007#define IOS  ios::sync_with_stdio(false)#define endl "\n"using namespace std;const int N = 2e5 + 10;unordered_map<int, unordered_map<int, int> > stu;int num[N];int p[N]; void init(int n) {    for (int i = 1; i <= n; i++) {        p[i] = i;        stu[i][num[i]] = 1;    }} int find(int x) {    return p[x] = p[x] == x ? x : find(p[x]);} void join(int x, int y) {    x = find(x);    y = find(y);    if (x != y) {        unordered_map<int, int>::iterator it;        if (stu[y].size() > stu[x].size()) {            p[x] = y;            for (it = stu[x].begin(); it != stu[x].end(); it++)                stu[y][it->first] += it->second;         } else {            p[y] = x;            for (it = stu[y].begin(); it != stu[y].end(); it++)                stu[x][it->first] += it->second;        }    }} int main() {#ifdef LOCAL    freopen("D:\\CPP\\input.in", "r", stdin);#endif    IOS;    int n, q;    cin >> n >> q;    for (int i = 1; i <= n; i++)        cin >> num[i];    init(n);    while (q--) {        int c, a, b;        cin >> c >> a >> b;        if (c == 1) {            join(a, b);        } else {            cout << stu[find(a)][b] << endl;        }    }    return 0;}/**************************************************************    Problem: 3165    User: 20320220114    Language: C++    Result: Accepted    Time:4797 ms    Memory:71352 kb****************************************************************/

Problem U

排列

Problem U: 排列Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 180 Solved: 41
[Submit] [Status] [Web Board] [Creator:editor]

Description

给定长度为N的由1 ~ N组成的序列a,给定M次操作 x,y,表示x位置可以和y位置进行交换,求解a[i]=i 的最大数量。

Input

第一行两个正整数N,M。
第二行N个数,表示序列a。
下面M行,总共M次操作,每行两个正整数x,y表示x位置可以和y位置进行交换。
2 ≤ N ≤ 105
1 ≤ M ≤ 105
1 ≤ x,y ≤ N (x ≠ y)

Output

输出a[i]=i 的最大数量。

Sample Input [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))
5 25 3 1 4 21 35 4
Sample Output [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))
2
HINT

a序列变成1 3 5 4 2,这是最优的,所以答案是2。

题解

可以交换的位置,就是一种叠加态,随意变化,就只看跟他相同的叠加态有没有可以改成的,其实就是并查集,看这个块里面有没有跟他一样的,有就直接变过去。

AC代码

// #define LOCAL#pragma gcc optimize(3) #include<iostream>#include<queue>#include<cstring>#include <algorithm>#include<map> #define IOS  ios::sync_with_stdio(false)using namespace std;const int N = 1e6 + 10;int p[N];int s[N];int k[N]; void init(int n) {    for (int i = 1; i <= n; i++) {        p[i] = i;    }} int find(int x) {    return p[x] = p[x] == x ? x : find(p[x]);} void book(int x, int y) {    x = find(x);    y = find(y);    if (x != y)        p[x] = y;}  int main() {#ifdef LOCAL    freopen("D:\\CPP\\input.in", "r", stdin);#endif    IOS;    int n, m;    int a, b;    cin >> n >> m;    for (int i = 1; i <= n; i++) {        cin >> s[i];        k[s[i]] = i;    }    init(n);    while (m--) {        cin >> a >> b;        book(a, b);    }    int ans = 0;    for (int i = 1; i <= n; i++) {        if (find(k[i]) == find(i))            ans++;    }    cout << ans << endl;    return 0;}/**************************************************************    Problem: 3166    User: 20320220114    Language: C++    Result: Accepted    Time:126 ms    Memory:13960 kb****************************************************************/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值