2019湖南多校第4场(codeforces gym 101158)部分题解

目录

A题:题目链接

B题:题目链接

C题:题目链接

D题:题目链接


A题:题目链接

题意:给定一个整数 n,代表有一个序列 1,2,3,4,...,n ,然后给定一个整数m, 接下来有 m 个数,代表把数 x 放在最前面。问最后这个序列是怎么样的。 ( n范围为 2e5)

思路:这是个煞笔题,开一个 4e5 + 10 的数组,数组起点设为 2e5, 输入放在 2e5后面,操作的数放在 2e5 前面,最后输出的时候判断这个数是否输出过,就ok了。

AC代码:

#include<bits/stdc++.h>
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define ull unsigned LL
#define INT(t) int t; scanf("%d",&t)
#define LLI(t) LL t; scanf("%I64d",&t)

using namespace std;

const int maxn = 4e5 + 10;
int a[maxn];
int vis[maxn];

int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        clr(vis,0);
        int l = 2e5;
        for(int i = l,j = 1;j <= n;++ j,++ i)
            a[i] = j;
        for(int i = 0;i < m;++ i){
            int tmp; scanf("%d",&tmp);
            a[-- l] = tmp;
        }
        for(int i = l;i < 2e5 + n;++ i)
            if(!vis[a[i]]){
                printf("%d\n",a[i]);
                vis[a[i]] = 1;
            }
    }
    return 0;
}

 

B题:题目链接

题意:这个题意有点傻逼,看了好久才明白。 假设一个四位数为  a,b,c,d   ,设 e = (((0⨂a)⨂b)⨂c)⨂d ,构成5位数  abcde。其中 x⨂y = table[x][y], table是一个表。            若将五位数 改变任意一位字符或交换相邻两个字符的位置产生的新五位数能满足 ((((0⨂a)⨂b)⨂c)⨂d)⨂e=0,则该数不可用。 最后判断 0000~9999 产生的 10000 个 五位数的总不可用数量。           注意:交换或者更换    不能和本身一样。

贴上代码:

 

#include<bits/stdc++.h>
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define ull unsigned LL
#define INT(t) int t; scanf("%d",&t)
#define LLI(t) LL t; scanf("%I64d",&t)

using namespace std;

int mp[20][20];
int a[10];
int ans = 0;

void getA(int num){
    for(int i = 3;i >= 0;-- i,num /= 10)
        a[i] = num % 10;
}

bool ok(){
    int res = 0;
    for(int k = 0;k < 5;++ k)
        res = mp[res][a[k]];
    return res == 0;
}

int change(int i){
    int tmp = a[i];
    for(int j = 0;j < 10;++ j){
        if(tmp == j) continue;
        a[i] = j;
        if(ok()){
            return -1;
        }
    }
    return tmp;
}

int main()
{
    for(int i = 0;i < 10;++ i)
        for(int j = 0;j < 10;++ j)
            scanf("%d",&mp[i][j]);
    int num = 0;
    while(num < 10000){
        getA(num);
        int res = 0;
        for(int i = 0;i < 4;++ i) res = mp[res][a[i]];
        a[4] = res;
        int flag = 0;
        for(int i = 0;i < 5;++ i){
            int k = change(i);
            if(k != -1) a[i] = k;
            if(k == -1){
                ++ ans;
                flag = 1;
                break;
            }
        }

        if(!flag){
            for(int i = 0;i < 4;++ i){
                swap(a[i],a[i + 1]);
                int tmp = 0;
                for(int j = 0;j <= 4;++ j) tmp = tmp * 10 + a[j];
                if(tmp == num * 10 + res) continue;
                if(ok()){
                    ++ ans;
                    break;
                }
                swap(a[i],a[i + 1]);
            }
        }
        ++ num;
    }
    printf("%d\n",ans);
    return 0;
}

 

C题:题目链接

题意:给定一个整数n,代表有 n 个传送带,然后是 m 个机器,有横坐标和纵坐标,例如为 (x,y),代表能够将第 y 个和第 y + 1个传送带的物品相互传送,问最后 每一个传送带右端   能够得到   多少个传送带左端传来的物品。

思路:首先是对于每一个机器按照横坐标大小排序。假设答案问字符数组 se[],代表第 i 层的答案为 se[i],显然起始时 se[i] = "i" 。我们用集合来模拟。    对于每一个机器  所连接的两个层数 y,y + 1,  显然可以相互达到,故 tmp = se[y]; se[y] += se[y + 1]; se[y + 1] += tmp;   (设为操作 )  但是需要去重。所以用set 会爆内存。

具体的,看看代码,这个不好解释。。。。。

#include<bits/stdc++.h>
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define ull unsigned LL
#define INT(t) int t; scanf("%d",&t)
#define LLI(t) LL t; scanf("%I64d",&t)

using namespace std;

const int maxn = 2e5 + 10;
struct xx{
    int t,d;
    int x;
}a[maxn / 2];
int se[maxn];
map<pair<int,int>,int>nnn;    /// pair 代表连接两个层, nnn,代表这两层之前的交集合大小
map<pair<int,int>,int>mp;

bool cmp(xx A,xx B){
    return A.x < B.x;
}

int main()
{
    int n,m; scanf("%d%d",&n,&m);
    for(int i = 0;i < m;++ i){
        int x,id; scanf("%d%d",&x,&id);
        a[i].x = x;
        a[i].t = id;
        a[i].d = id + 1;
    }
    for(int i = 1;i <= n;++ i)
        se[i] = 1;
    sort(a,a + m,cmp);
    int tmp;
    nnn.clear();
    mp.clear();
    for(int i = 0;i < m;++ i){
        int t = a[i].t;
        int d = a[i].d;
        if(!mp.count(MP(t,d))){
            tmp = se[t];
            se[t] += se[d];
            se[d] += tmp;
            mp[MP(t,d)] = 1;
            nnn[MP(t,d)] = se[t];    /// 你会发现 操作之后, (se[t],se[d])之前的交集大小,就是 se[t]
        }
        else {
            int f = nnn[MP(t,d)];
            int tmp = se[t] - f + se[d] - f;
            se[t] = se[d] = f + tmp;
            nnn[MP(t,d)] = se[t];   /// 你会发现 操作之后, (se[t],se[d])之前的交集大小,就是 se[t]
        }
    }
    for(int j = 1;j <= n;++ j)
        printf("%d ",se[j]);
    return 0;
}

 

D题:题目链接

题意:给定两个字符串,要找出两个字符串的最长公共子序列长度,这里的最长公共子序列指  连续的序列,在另一个序列中不用考虑顺序。如   amdsfdn  和  dmasgggg   其中  amds, dmas, 分别在两个串中都是连续的,且不考虑顺序的情况下,这两个串是相同的,所以答案就是  4.

(毒瘤3哈希)思路:暴力 + hash,求一个串所有的哈希值,然后判断另一串是否也有这个哈希值出现。我代码的哈希就很简单了,直接用一个数代表一个字符, 然后用前缀和求的所有的哈希值,由于这样哈希的碰撞会很大,所以用的3hash。

(简短单哈希。)思路:正常的单哈希,类26进制(自己发明的名词)代表一个字符串。为什么可以,我大概解释一下,类26进制也就是26位每一位存字母出现的个数(而且不逢26进1)然后每一位的权重就和2进制相似,假如  abababa,  就是(省略24个0) 3 4    ,当然是可能存在碰撞的,比如 26个a,和1个 b, 他们的哈希值是一样的。但是我们是枚举答案的长度,然后计算哈希值,   也就是  要同时满足长度一样,而且哈希值还要相同,   这样的情况(应该是不可能存在的)。

毒瘤3哈希代码:(比较毒瘤)

#include<bits/stdc++.h>
#define fuck(x) std::cout<<"["<<#x<<"->"<<x<<"]"<<endl;
using namespace std;
typedef long long ll;

const int mod = 1e9 + 7;
ll a[4005] = {131,17162,2248224,294517347,581772195,212157018,792569175,826561211,279517893,616843740,806529390,655349366,850766363,450392789,1454960,190599775,968570373,882717998,636056951,323460019,373262215,897349850,552829553,420670962,107895661,134331518};
ll a1[4005] = {2,5,12,27,58,121,248,503,1014,2037,4084,8179,16370,32753,65520,131055,262126,524269,1048556,2097131,4194282,8388585,16777192,33554407,67108838,134217701};//13
ll a2[4005] = {13331,177715562,126140441,578207207,80222565,447006537,44103040,937622138,440634193,94385774,256744398,659545795,404931613,143295130,267364674,238444161,699088061,542875975,79572084,775444403,449264054,139061972,835135783,195045265,148409539,447550588};

char x[4005];
char y[4005];

unordered_map<int, int>mp11, mp21, mp12, mp13, mp22, mp23;

int premul11[4005];
int premul12[4005];
int premul13[4005];
int premul21[4005];
int premul22[4005];
int premul23[4005];

int main() {
    scanf("%s", x);
    scanf("%s", y);
    int len1 = strlen(x), len2 = strlen(y);
    int len = min(len1, len2);
    int ans = 0;
    premul11[0] = premul12[0] = premul13[0] = 0;
    premul21[0] = premul22[0] = premul23[0] = 0;
    premul11[1] = a[x[0] - 97];
    premul12[1] = a1[x[0] - 97];
    premul13[1] = a2[x[0] - 97];

    premul21[1] = a[y[0] - 97];
    premul22[1] = a1[y[0] - 97];
    premul23[1] = a2[y[0] - 97];
    for(int i = 2; i <= len1; i++) {
        premul11[i] = (premul11[i - 1] + a[x[i - 1] - 97]) % mod;
        premul12[i] = (premul12[i - 1] + a1[x[i - 1] - 97]) % mod;
        premul13[i] = (premul13[i - 1] + a2[x[i - 1] - 97]) % mod;
    }
    for(int i = 2; i <= len2; i++) {
        premul21[i] = (premul21[i - 1] + a[y[i - 1] - 97]) % mod;
        premul22[i] = (premul22[i - 1] + a1[y[i - 1] - 97]) % mod;
        premul23[i] = (premul23[i - 1] + a2[y[i - 1] - 97]) % mod;
    }

    for(int i = len; i > 0; i--) {
        mp11.clear();mp12.clear();mp13.clear();
        mp21.clear();mp22.clear();mp23.clear();
        for(int j = 0; j + i <= len1; j++) {
            mp11[(premul11[j + i] - premul11[j] + mod) % mod] = 1;
            mp12[(premul12[j + i] - premul12[j] + mod) % mod] = 1;
            mp13[(premul13[j + i] - premul13[j] + mod) % mod] = 1;
        }
        for(int j = 0; j + i <= len2; j++){
            mp21[(premul21[j + i] - premul21[j] + mod) % mod] = 1;
            mp22[(premul22[j + i] - premul22[j] + mod) % mod] = 1;
            mp23[(premul23[j + i] - premul23[j] + mod) % mod] = 1;
        }
        int xxxxx = 0;
        for(auto xx : mp11) {
            if(mp21.count(xx.first) == 1) {
                ans = i;
                ++ xxxxx;
                break;
            }
        }
        for(auto xx : mp12) {
            if(mp22.count(xx.first) == 1) {
                ans = i;
                ++ xxxxx;
                break;
            }
        }
        for(auto xx : mp13) {
            if(mp23.count(xx.first) == 1) {
                ans = i;
                ++ xxxxx;
                break;
            }
        }
        if(xxxxx == 3)
            break;
    }
    printf("%d\n", ans);
    return 0;
}

单哈希代码:

#include<bits/stdc++.h>
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define ull unsigned LL
#define INT(t) int t; scanf("%d",&t)
#define LLI(t) LL t; scanf("%I64d",&t)

using namespace std;

const int maxn = 4100;
char a[maxn], b[maxn];

unordered_map<ull, int> mp1, mp2;
int sums[30][maxn];
int sumt[30][maxn];
ull pow1[30];

ull getHashS(int x, int l, int r) {
    return pow1[x] * (ull)(sums[x][r] - sums[x][l - 1]);
}

ull getHashT(int x, int l, int r) {
    return pow1[x] * (ull)(sumt[x][r] - sumt[x][l - 1]);
}

int main() {
    pow1[0] = 1;
    for(int i = 1; i < 30; ++ i)
        pow1[i] = pow1[i - 1] * 26;
    scanf("%s%s", a + 1, b + 1);
    int lena = strlen(a + 1), lenb = strlen(b + 1);
    clr(sums, 0);
    clr(sumt, 0);
    for(int i = 1; i <= lena; ++ i) {
        for(char j = 'a'; j <= 'z'; ++ j) {
            sums[j - 'a'][i] = sums[j - 'a'][i - 1] + (a[i] == j);
        }
    }
    for(int i = 1; i <= lenb; ++ i) {
        for(char j = 'a'; j <= 'z'; ++ j) {
            sumt[j - 'a'][i] = sumt[j - 'a'][i - 1] + (b[i] == j);
        }
    }
    int len = min(lena, lenb);
    int ans = 0;
    for(int i = len; i > 0; -- i) {
        mp1.clear();
        mp2.clear();
        ull tmp = 0;
        for(int j = 1; j + i - 1 <= lena; ++ j) {
            tmp = 0;
            for(int k = 0; k < 26; ++ k)
                tmp += getHashS(k, j, j + i - 1);
            mp1[tmp] = 1;
            //debug(tmp);
        }
        //cout << endl << endl;
        for(int j = 1; j + i - 1 <= lenb; ++ j) {
            tmp = 0;
            for(int k = 0; k < 26; ++ k)
                tmp += getHashT(k, j, j + i - 1);
            mp2[tmp] = 1;
            //debug(tmp);
        }//cout << " 1" << endl;
        int flag = 0;
        for(auto it : mp1)
            if(mp2.count(it.first)) {
                ans = i;
                flag = 1;
                break;
            }
        if(flag)
            break;
    }
    cout << ans << endl;
    return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值