首页 > 其他分享 >2023冲刺国赛模拟 5.1

2023冲刺国赛模拟 5.1

时间:2023-05-26 19:57:49浏览次数:44  
标签:5.1 const int sum h1 国赛 2023 Hash include

最近感觉自己越来越摆了,看到各位大佬洛谷的月通过量都 100 以上感到十分震惊,不像我这个废物月通过量只有 30 。

T1 无限之环

考虑互为子串的两个字符串,容易发现两个串的 \(B\) 部分字母所组成的集合一定完全相同,考虑两个串的 \(A\) 部分,如果 \(A\) 部分的末尾字符属于 \(B\) 部分字母所组成的集合,那么这个字符显然可以和 \(B\) 部分进行匹配,可以直接将这样的末尾字符删去,不难发现两个串剩余的 \(A\) 部分一定完全相等。

比较显然的做法是将所有串按照 \(B\) 部分字母所组成的集合以及剩余的 \(A\) 部分进行分组,直接输出每组内包含的字符串即可。

code
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <cstring>
#include <vector>
using namespace std;

const int max1 = 1e6;
const int base = 29, mod1 = 998244353, mod2 = 20051107;

int n;
char A[max1 + 5], B[max1 + 5];

struct Hash
{
    int h1, h2;

    Hash () {}
    Hash ( int __h1, int __h2 )
        { h1 = __h1, h2 = __h2; }
    
    Hash operator + ( const Hash &A ) const
        { return Hash(( h1 + A.h1 ) % mod1, ( h2 + A.h2 ) % mod2); }
    Hash operator * ( const Hash &A ) const 
        { return Hash(1LL * h1 * A.h1 % mod1, 1LL * h2 * A.h2 % mod2); }
    
    bool operator == ( const Hash &A ) const
        { return h1 == A.h1 && h2 == A.h2; }
    bool operator < ( const Hash &A ) const
    {
        if ( h1 != A.h1 )
            return h1 < A.h1;
        return h2 < A.h2;
    }
};

struct Data
{
    int s; Hash h;

    Data () {}
    Data ( int __s, Hash __h )
        { s = __s, h = __h; }
    
    bool operator < ( const Data &A ) const
    {
        if ( s != A.s )
            return s < A.s;
        return h < A.h;
    }
};

map <Data, int> Map;

vector <int> id[max1 + 5];
int total;

int main ()
{
    freopen("infty.in", "r", stdin);
    freopen("infty.out", "w", stdout);

    scanf("%d", &n);
    for ( int i = 1; i <= n; i ++ )
    {
        scanf("%s%s", A + 1, B + 1);
        int len;

        int s = 0;
        if ( B[1] != '=' )
        {
            len = strlen(B + 1);
            for ( int k = 1; k <= len; k ++ )
                s |= 1 << B[k] - 'a';
        }
        
        Hash h = Hash(0, 0);
        if ( A[1] != '=' )
        {
            len = strlen(A + 1);
            while ( len && ( s >> ( A[len] - 'a' ) & 1 ) )
                --len;
            
            for ( int k = 1; k <= len; k ++ )
                h = h * Hash(base, base) + Hash(A[k] - 'a' + 1, A[k] - 'a' + 1);
        }

        if ( Map.find(Data(s, h)) == Map.end() )
            Map[Data(s, h)] = ++total;

        id[Map[Data(s, h)]].push_back(i);
    }

    printf("%d\n", total);
    for ( int i = 1; i <= total; i ++ )
    {
        printf("%lu ", id[i].size());
        for ( auto v : id[i] )
            printf("%d ", v);
        printf("\n");
    }

    return 0;
}

T2 变化多端

考虑按照从内到外的顺序依次枚举每个马槽,从这个马槽开始 Bfs ,找到最近的马后将其移动到这个马槽即可,马的数量较多的时候可以改为移动空格(显然几乎没有优化)。

code
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#include <vector>
#include <utility>
#include <iostream>
using namespace std;

const int lim = 8, sum = 64;
const int inf = 0x3f3f3f3f;

int n;
bool block[sum + 5], vis[sum + 5], koi[sum + 5], done[sum + 5], rev;
int point[sum + 5], dis[sum + 5], pre[sum + 5];

queue <int> que;

vector < pair <int, int> > ans;

bool Bfs ( int s )
{
    if ( block[s] )
        { done[s] = true; return true; }

    memset(vis, 0, sizeof(bool) * sum);
    memset(dis, 0x3f, sizeof(int) * sum);
    memset(pre, -1, sizeof(int) * sum);
    while ( !que.empty() )
        que.pop();

    dis[s] = 0; vis[s] = true; que.push(s);

    while ( !que.empty() )
    {
        int now = que.front();
        que.pop();

        int x = now >> 3, y = now & 7;
        int v;

        if ( x > 0 && y > 1 )
        {
            v = ( x - 1 ) << 3 | ( y - 2 );

            if ( !done[v] && !vis[v] )
            {
                dis[v] = dis[now] + 1;
                que.push(v);
                vis[v] = true;
                pre[v] = now;
                
                if ( block[v] )
                    break;
            }
        }

        if ( x > 0 && y < 6 )
        {
            v = ( x - 1 ) << 3 | ( y + 2 );

            if ( !done[v] && !vis[v] )
            {
                dis[v] = dis[now] + 1;
                que.push(v);
                vis[v] = true;
                pre[v] = now;
                
                if ( block[v] )
                    break;
            }
        }

        if ( x < 7 && y > 1 )
        {
            v = ( x + 1 ) << 3 | ( y - 2 );

            if ( !done[v] && !vis[v] )
            {
                dis[v] = dis[now] + 1;
                que.push(v);
                vis[v] = true;
                pre[v] = now;
                
                if ( block[v] )
                    break;
            }
        }

        if ( x < 7 && y < 6 )
        {
            v = ( x + 1 ) << 3 | ( y + 2 );

            if ( !done[v] && !vis[v] )
            {
                dis[v] = dis[now] + 1;
                que.push(v);
                vis[v] = true;
                pre[v] = now;
                
                if ( block[v] )
                    break;
            }
        }

        if ( x > 1 && y > 0 )
        {
            v = ( x - 2 ) << 3 | ( y - 1 );

            if ( !done[v] && !vis[v] )
            {
                dis[v] = dis[now] + 1;
                que.push(v);
                vis[v] = true;
                pre[v] = now;
                
                if ( block[v] )
                    break;
            }
        }

        if ( x > 1 && y < 7 )
        {
            v = ( x - 2 ) << 3 | ( y + 1 );

            if ( !done[v] && !vis[v] )
            {
                dis[v] = dis[now] + 1;
                que.push(v);
                vis[v] = true;
                pre[v] = now;
                
                if ( block[v] )
                    break;
            }
        }

        if ( x < 6 && y > 0 )
        {
            v = ( x + 2 ) << 3 | ( y - 1 );

            if ( !done[v] && !vis[v] )
            {
                dis[v] = dis[now] + 1;
                que.push(v);
                vis[v] = true;
                pre[v] = now;
                
                if ( block[v] )
                    break;
            }
        }

        if ( x < 6 && y < 7 )
        {
            v = ( x + 2 ) << 3 | ( y + 1 );

            if ( !done[v] && !vis[v] )
            {
                dis[v] = dis[now] + 1;
                que.push(v);
                vis[v] = true;
                pre[v] = now;
                
                if ( block[v] )
                    break;
            }
        }
    }

    for ( int i = 0; i < sum; i ++ )
    {
        if ( block[i] && dis[i] != inf )
        {
            int now = i;
            while ( now != s )
            {
                ans.push_back(make_pair(now, pre[now]));
                now = pre[now];
            }

            block[i] = false;
            block[s] = true;
            done[s] = true;

            break;
        }
    }

    return true;
}

void Update ()
{
    if ( !rev )
    {
        for ( int y = 0; y < lim; y ++ )
        {
            for ( int x = 0; x < lim; x ++ )
            {
                int p = x << 3 | y;

                if ( koi[p] && !done[p] && Bfs(p) )
                    return;
            }
        }
    }
    else
    {
        for ( int y = lim - 1; y >= 0; y -- )
        {
            for ( int x = lim - 1; x >= 0; x -- )
            {
                int p = x << 3 | y;

                if ( koi[p] && !done[p] && Bfs(p) )
                    return;
            }
        }
    }
    return;
}

int main ()
{
    freopen("changeful.in", "r", stdin);
    freopen("changeful.out", "w", stdout);

    scanf("%d", &n);

    char s[5];
    for ( int i = 1; i <= n; i ++ )
    {
        scanf("%s", s);
        point[i] = ( s[0] - 'a' ) << 3 | ( s[1] - '1' );

        block[point[i]] = true;
    }

    for ( int i = 0; i < ( n >> 3 ); i ++ )
    {
        for ( int j = 0; j < lim; j ++ )
        {
            int x = j << 3 | i;
            koi[x] = true;
        }
    }

    for ( int j = 0; j < ( n & 7 ); j ++ )
    {
        int x = j << 3 | ( n >> 3 );
        koi[x] = true;
    }

    if ( n > ( sum >> 1 ) )
    {
        rev = true; n = 0;
        for ( int i = 0; i < sum; i ++ )
        {
            if ( !block[i] )
                point[++n] = i;

            block[i] ^= 1;
            koi[i] ^= 1;
        }
    }

    for ( int i = 1; i <= n; i ++ )
        Update();

    if ( rev )
        for ( auto &p : ans )
            swap(p.first, p.second);
        
    printf("%lu\n", ans.size());
    for ( auto p : ans )
    {
        putchar('a' + ( p.first >> 3 ));
        putchar('1' + ( p.first & 7 ));
        putchar('-');
        putchar('a' + ( p.second >> 3 ));
        putchar('1' + ( p.second & 7 ));
        putchar('\n');
    }
    
    return 0;
}

T3 活罪难赦

考虑分析平衡串的性质,对于 \(x\) ,我们从高向低依次考虑每一位,如果最高位为 \(0\) ,显然平衡串的前后两个部分完全相同,如果最高位为 \(1\) ,显然平衡串的前后两个部分完全相反。

考虑到每次操作为区间取反,这并不好实现,比较套路的想法是对原串进行异或差分,因此分析平衡串的差分数组的性质,设 \(t_i=s_{i-1}\oplus s_i\) ,由于平衡串前后完全相同或者完全相反,因此前后做差分实际上完全相同,特殊的,差分数组中间位置取值任意。

注意到题目给定 \(b\) ,表示对平衡串整体取反不会产生代价,因此我们只需要考虑平衡串一些位置上的值相等,而不需要考虑其具体的取值。

一个比较显然的 \(O(nq)\) 暴力是取出所有满足取值相等的位置,统计这些位置中 \(0,1\) 的个数,然后将 \(\min(cnt_0,cnt_1)\) 统计入答案中。

观察这些取值相等的位置的特点,发现这些位置的 lowbit 相等,因此可以预处理每个位置 \(i\) 到 \(n\) 的子串内,满足下标 lowbit 为 \(2^k\) 的差分数组中 \(1\) 的个数 \(sum_{i,k}\) ,查询时枚举每个 lowbit 统计贡献即可,复杂度 \(O((n+q)\log n)\) 。

code
#include <cstdio>
#include <algorithm>
using namespace std;

const int max1 = 3e5;

int n, q, a[max1 + 5];
char s[max1 + 5];
int sum[max1 + 5][20];

int main ()
{
    freopen("sins.in", "r", stdin);
    freopen("sins.out", "w", stdout);

    scanf("%d%s", &n, s);
    for ( int i = 0; i < n; i ++ )
        a[i] = s[i] - '0';
    for ( int i = n - 1; i >= 1; i -- )
        a[i] = a[i] ^ a[i - 1];

    for ( int k = 0; ( 1 << k ) <= n; k ++ )
    {
        for ( int i = n - 1; i >= 0; i -- )
        {
            if ( i + ( 1 << k ) < n )
            {
                sum[i][k] = sum[i + ( 1 << k )][k];
                sum[i][k] += a[i + ( 1 << k )];
            }
        }
    }

    for ( int i = 0; i <= n - 1; i ++ )
        for ( int k = 0; ( 1 << k ) <= n; k ++ )
            sum[i][k] -= sum[i][k + 1];

    scanf("%d", &q);

    int L, R, ans;
    while ( q -- )
    {
        scanf("%d%d", &L, &R);
        ans = 0;
        for ( int k = 0; ( 1 << k + 1 ) <= R - L + 1; k ++ )
            ans += min(sum[L][k] - sum[R + 1][k], ( R - L + 1 ) / ( 1 << k + 1 ) - ( sum[L][k] - sum[R + 1][k] ));
        
        printf("%d\n", ans + 1 >> 1);
    }

    return 0;
}

标签:5.1,const,int,sum,h1,国赛,2023,Hash,include
From: https://www.cnblogs.com/KafuuChinocpp/p/17435664.html

相关文章

  • 2023.5.26每日总结
    packageservlets;importjava.io.IOException;importjava.util.ArrayList;importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjava......
  • 以云原生推动代际跃升,2023通明湖论坛云原生分论坛召开
    5月12日,由神州数码主办,北京经开区国家信创园、中关村云计算产业联盟协办的2023通明湖论坛-云原生分论坛在京召开。本次论坛,以“抓住云原生机遇,推动我国信息基础设施技术代际跃升”为主题,聚焦以云原生为核心引领的科技革命和产业革命,共同探讨云原生为我国信息基础设施技术发展提供的......
  • 2023.5.26——软件工程日报
    所花时间(包括上课):6h代码量(行):0行博客量(篇):1篇今天,上午学习,下午学习。我了解到的知识点:1.了解了一些数据库的知识;2.了解了一些python的知识;3.了解了一些英语知识;5.了解了一些Javaweb的知识;4.了解了一些数学建模的知识;6.了解了一些计算机网络的知识;......
  • 2023.5.26——软件工程站立会议(阶段二)
    站立会议内容:1.整个项目预期的任务量:目前已经花的时间:剩余的时间:2.任务看板照片: 3.团队照片: 4.产品状态:最新做好的功能:正在完成中5.燃尽图:......
  • 2023.5.26编程一小时打卡
    一、问题描述:定义复数类MyComplex,主函数完成相关测试。MyComplex类结构说明:1、数据成员包括:私有数据成员:实部x(double)虚部y(double)。2、成员函数包括:无参构造函数MyComplex(void),其功能是将数据成员数部和虚部的值均设为0;有参构造函数MyComplex(doublevalue1,doublevalue2),其功能......
  • 【2023最新】超详细图文保姆级教程:App开发新手入门(6)
    9.编译正式版 本章我们简单介绍一下如何设置应用的桌面图标及应用的启动页 通过之前章节的学习,我们已经完成了一个简单应用的开发,本部分章节主要目的是为本系列教程进行一个整体性的收尾,简介讲解一下如何编译一个可用于上架应用市场的正式版安装包。(本章内容超级简单......
  • 2023最新多端社交圈子系统源码 | 陌生人社交 | 即时聊天通信 | 小程序+H5+PC+APP等多
     DUOKE多客圈子论坛社区系统,含完整的后台PHP系统。功能:小程序授权登陆,H5和APP,手机号登陆,发帖,建圈子、发活动。圈主可置顶推荐帖子,关注、粉丝、点赞等。可作为圈子贴吧、小红书等自媒体。下载地址直接点击群聊插件单独频道功能说明:1、可申请建群。后台审核,2、群分为自由加入......
  • M洞察|“MOBA”还是“MMO”?2023上半年热门手游大盘点来了,拯救你的游戏荒
    2023年Q1中国移动游戏市场整体表现不及预期,实际销售收入为486.94亿元,同比下降19.42%。虽整体有所下滑,但新鲜血液依然迸发强劲。3月22日,一款玩法轻松、新颖的种田类手游《桃源深处有人家》正式上线,玩家纷纷投入其中,化身萝萝山的村民,共同建设美丽新农村。而4月26日备受关注的米哈游新......
  • 【2023最新】超详细图文保姆级教程:App开发新手入门(2)
    上章节我们已经成功的创建了一个App项目,接下来我们讲述一下,如何导入项目、编辑代码和提交项目代码。 Let’sGo! 4.项目导入 当用户创建一个新的应用时,YonStudio开发工具会自动导入模板项目的默认代码,不需要手动进行代码导入。那么当我们不是创建应用,而是需要导入一个已经存......
  • 【2023最新】超详细图文保姆级教程:App开发新手入门(3)
    上文回顾,我们已经完成了一个应用项目创建、导入、代码更新、代码同步和代码提交,本章继续我们的新手开发之旅,讲述一下如何将开发完成的应用进行编译,生成可供他人安装、可上架的应用安装包。6应用打包 应用打包,简单来说就是将编写的代码,通过工具的打包编译机制,打包编译生成对应的手......