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

2023冲刺国赛模拟 33.1

时间:2023-07-10 16:02:58浏览次数:40  
标签:include 33.1 int siz sum max1 国赛 2023 now

T1 染色

直接操作分块,可以做到 \(O(n\sqrt{n})\) 。(显然树剖求 lca 约为 \(O(1)\) )

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

const int max1 = 1e5, B = 300;

int n, m;
vector <int> edge[max1 + 5];

int father[max1 + 5], val[max1 + 5];
long long sum[max1 + 5];
int siz[max1 + 5], deep[max1 + 5], son[max1 + 5];
int top[max1 + 5], dfn[max1 + 5], rk[max1 + 5], dfs_clock;

int tmp[max1 + 5], len;

bool black[max1 + 5];
int cnt[max1 + 5];
long long f[max1 + 5], g[max1 + 5];

void Find_Heavy_Edge ( int now, int depth )
{
    sum[now] = sum[father[now]] + val[now];
    siz[now] = 1, deep[now] = depth, son[now] = 0;

    int max_siz = 0;
    for ( auto v : edge[now] )
    {
        Find_Heavy_Edge(v, depth + 1);

        if ( siz[v] > max_siz )
            max_siz = siz[v], son[now] = v;
        
        siz[now] += siz[v];
    }
    return;
}

void Connect_Heavy_Edge ( int now, int ancestor )
{
    top[now] = ancestor;
    dfn[now] = ++dfs_clock;
    rk[dfs_clock] = now;
    if ( son[now] )
        Connect_Heavy_Edge(son[now], ancestor);
    
    for ( auto v : edge[now] )
    {
        if ( v == son[now] )
            continue;
        
        Connect_Heavy_Edge(v, v);
    }
    return;
}

int Get_Lca ( int u, int v )
{
    while ( top[u] != top[v] )
    {
        if ( deep[top[u]] < deep[top[v]] )
            swap(u, v);
        u = father[top[u]];
    }

    if ( deep[u] > deep[v] )
        swap(u, v);
    return u;
}

long long Get_Dis ( int u, int v )
{
    return sum[u] + sum[v] - (sum[Get_Lca(u, v)] << 1);
}

void Solve ()
{
    memset(cnt + 1, 0, sizeof(int) * n);
    memset(f + 1, 0, sizeof(long long) * n);
    len = 0;

    for ( int i = n; i >= 2; i -- )
    {
        int now = rk[i];
        cnt[now] += (int) black[now];

        f[father[now]] += f[now] + 1LL * cnt[now] * val[now];
        cnt[father[now]] += cnt[now];
    }
    cnt[1] += (int) black[1];

    g[1] = f[1];
    for ( int i = 2; i <= n; i ++ )
    {
        int now = rk[i];
        g[now] = g[father[now]] + 1LL * (cnt[1] - cnt[now] - cnt[now]) * val[now];
    }
    return;
}

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

    scanf("%d%d", &n, &m);
    for ( int i = 2; i <= n; i ++ )
    {
        scanf("%d", &father[i]); ++father[i];
        edge[father[i]].push_back(i);
    }

    for ( int i = 2; i <= n; i ++ )
        scanf("%d", &val[i]);

    Find_Heavy_Edge(1, 0);
    Connect_Heavy_Edge(1, 1);

    int opt, x;
    for ( int i = 1; i <= m; i ++ )
    {
        scanf("%d%d", &opt, &x); ++x;
        if ( opt == 1 )
        {
            if ( !black[x] )
            {
                tmp[++len] = x;
                black[x] = true;
            }
        }
        else
        {
            long long ans = g[x];
            for ( int k = 1; k <= len; k ++ )
                ans += Get_Dis(x, tmp[k]);
            printf("%lld\n", ans);
        }

        if ( !(i % B) )
            Solve();
    }

    return 0;
}

T2 寻宝游戏

题目给出了判定一个点是否在多边形内的方法,由于这只与射线经过的边的奇偶性有关,因此考虑状压奇偶性。

设 \(f_{i, j, S}\) 表示当前位于点 \((i, j)\) ,宝藏和陷阱的奇偶性为 \(S\) 的最短移动次数,大力 Bfs 转移即可。

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

const int max1 = 20;
const int inf = 1e8;
const int dx[] = { -1, 1, 0, 0 }, dy[] = { 0, 0, -1, 1 };

int n, m, k;
char mp[max1 + 5][max1 + 5];
int px[max1 + 5], py[max1 + 5], val[max1 + 5];

int f[max1 + 5][max1 + 5][1 << 8];

struct Point
{
    int x, y, S;

    Point () {}
    Point ( int __x, int __y, int __S )
        { x = __x, y = __y, S = __S; }
};

queue <Point> que;

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

    scanf("%d%d", &n, &m);
    for ( int i = 1; i <= n; i ++ )
        scanf("%s", mp[i] + 1);
    
    for ( int i = 1; i <= n; i ++ )
    {
        for ( int j = 1; j <= m; j ++ )
        {
            if ( mp[i][j] >= '0' && mp[i][j] <= '9' )
            {
                ++k;
                px[mp[i][j] - '0'] = i;
                py[mp[i][j] - '0'] = j;
            }
        }
    }
    
    for ( int i = 1; i <= k; i ++ )
        scanf("%d", &val[i]);
    
    Point p;

    for ( int i = 1; i <= n; i ++ )
    {
        for ( int j = 1; j <= m; j ++ )
        {
            if ( mp[i][j] == 'B' )
            {
                ++k;
                px[k] = i;
                py[k] = j;
                val[k] = -inf;
            }

            if ( mp[i][j] == 'S' )
                p = Point(i, j, 0), que.push(p);
        }
    }

    for ( int i = 1; i <= n; i ++ )
        for ( int j = 1; j <= m; j ++ )
            for ( int S = 0; S < (1 << k); S ++ )
                f[i][j][S] = inf;
    
    f[p.x][p.y][p.S] = 0;

    while ( !que.empty() )
    {
        int x = que.front().x, y = que.front().y, S = que.front().S;
        que.pop();

        for ( int i = 0; i < 4; i ++ )
        {
            int nx = x + dx[i], ny = y + dy[i];
            if ( nx < 1 || nx > n || ny < 1 || ny > m || (mp[nx][ny] != '.' && mp[nx][ny] != 'S') )
                continue;
            
            int nS = S;
            if ( i < 2 )
            {
                for ( int j = 1; j <= k; j ++ )
                    if ( min(x, nx) == px[j] && py[j] > ny )
                        nS ^= 1 << (j - 1);
            }

            if ( f[nx][ny][nS] == inf )
            {
                f[nx][ny][nS] = f[x][y][S] + 1;
                que.push(Point(nx, ny, nS));
            }
        }
    }

    int ans = 0;
    for ( int S = 0; S < (1 << k); S ++ )
    {
        if ( f[p.x][p.y][S] == inf )
            continue;

        int up = -f[p.x][p.y][S];
        for ( int i = 1; i <= k; i ++ )
            up += ((S >> (i - 1)) & 1) * val[i];
        
        ans = max(ans, up);
    }

    printf("%d\n", ans);

    return 0;
}

T3 点分治

发现需要求解的就是本质不同的点分树的数量,没有办法根据删点的过程划分子问题,因此考虑最朴素的树形 dp 。

考虑一条边 \((u, v)\) ,如果我们已经得到 \(u, v\) 子树形成的点分树,考虑进行合并。

考虑合并后的点分树的根节点,容易发现这只能是 \(u\) 子树点分树的根节点或 \(v\) 子树点分树的根节点,如果根节点为 \(u\) 子树点分树的根节点,容易发现 \(u\) 子树点分树根节点中除 \(u\) 节点所在子树的其余儿子,一定为当前根节点的儿子,因此将这些部分删去,剩余部分仍然为两棵点分树,可以直接递归进行合并。容易发现 \(u\) 或 \(v\) 节点被删去后合并终止。

发现合并过程产生的贡献只与 \(u, v\) 节点在点分树中的深度有关,因此设 \(f_{u, i}\) 表示以 \(u\) 为根的子树, \(u\) 节点在点分树中的深度为 \(i\) 的方案数。转移考虑 \(u, v\) 节点哪个先被删去,如果 \(u\) 先被删去,枚举 \(v\) 点分树中在 \(u\) 之前被删去的深度进行转移; \(v\) 节点先被删去同理。简单优化可以做到 \(O(n^2)\) 。

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

const int max1 = 5000;
const int mod = 1e9 + 7;

int n;
vector <int> edge[max1 + 5];

int C[max1 + 5][max1 + 5];
int siz[max1 + 5], f[max1 + 5][max1 + 5], tmp[max1 + 5], sum[max1 + 5];

void Dfs ( int now, int fa )
{
    siz[now] = 1;
    f[now][1] = 1;

    for ( auto v : edge[now] )
    {
        if ( v == fa )
            continue;
        
        Dfs(v, now);
        memcpy(tmp + 1, f[now] + 1, sizeof(int) * siz[now]);
        memset(f[now] + 1, 0, sizeof(int) * (siz[now] + siz[v]));

        sum[siz[v] + 1] = 0;
        for ( int i = siz[v]; i >= 1; i -- )
            sum[i] = (sum[i + 1] + f[v][i]) % mod;
        
        for ( int i = 1; i <= siz[now]; i ++ )
            for ( int k = 1; k <= siz[v]; k ++ )
                f[now][i + k - 1] = (f[now][i + k - 1] + 1LL * tmp[i] * C[i - 1 + k - 1][i - 1] % mod * sum[k]) % mod;
        
        for ( int j = 1; j <= siz[v]; j ++ )
        {
            sum[0] = 0;
            for ( int i = 1; i <= siz[now]; i ++ )
                sum[i] = (sum[i - 1] + C[i - 1 + j - 1][j - 1]) % mod;
            for ( int i = 1; i <= siz[now]; i ++ )
                f[now][i + j] = (f[now][i + j] + 1LL * tmp[i] * f[v][j] % mod * sum[i]) % mod;
        }
        siz[now] += siz[v];
    }
    return;
}

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

    scanf("%d", &n);
    for ( int i = 2, u, v; i <= n; i ++ )
    {
        scanf("%d%d", &u, &v);
        edge[u].push_back(v);
        edge[v].push_back(u);
    }

    C[0][0] = 1;
    for ( int i = 1; i <= n; i ++ )
    {
        C[i][0] = 1;
        for ( int j = 1; j <= i; j ++ )
            C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
    }

    Dfs(1, 0);

    int ans = 0;
    for ( int i = 1; i <= n; i ++ )
        ans = (ans + f[1][i]) % mod;
    printf("%d\n", ans);

    return 0;
}

标签:include,33.1,int,siz,sum,max1,国赛,2023,now
From: https://www.cnblogs.com/KafuuChinocpp/p/17541406.html

相关文章

  • 硬核!阿里2023版Spring全家桶进阶笔记流出,堪称Java跳槽神器
    最近小伙伴在我后台留言是这样的: 现在就这光景,不比以前,会个CRUD就有人要,即使大部分公司依然只需要做CRUD的事情......现在去面试,只会CRUD还要被吐槽: 面试造火箭,工作拧螺丝,就是现在互联网最真实的写照。很多程序员都是死磕八股文,以应对面试。这种情况无可厚非,但其实最重......
  • 第三届应用物理与能源发展国际学术会议(APED2023)
    第三届应用物理与能源发展国际会议(APED2023)将于2023年12月2-3日在中国北京召开。APED2023旨在汇集应用物理和能源开发领域的创新学者和行业专家,交流思想,展示先进的研究成果并讨论热点话题,我们热烈邀请您参加APED2023!★重要信息大会地点:中国-北京大会时间:2023年12月2-3日截......
  • 2023最新版本WebStrom安装教程【2023.1.3】
    前言本文方法可以安装使用截止当前2023.1.3最新版本WebStrom,过程非常简单,按照下面的步骤来一分钟即可搞定。1.下载安装已经安装过的可以跳过该步骤!下载到官网地址下载正版安装包JetBrainsWebStrom官网下载地址安装开始安装选择安装路径桌面快捷方式勾选创建妆......
  • 2023年6月国产数据库大事记-墨天轮
    本文为墨天轮社区整理的2023年6月国产数据库大事件和重要产品发布消息。目录6月国产数据库大事记(时间线)产品/版本发布兼容认证代表厂商大事记排行榜新增数据库厂商活动相关资料6月国产数据库大事记(时间线)6月1日,中国实时数据库厂商北京飞轮数据科技有限公司完成了又一......
  • 2023.7.10
    1importjava.util.Scanner;23publicclasstest4{5publicstaticvoidmain(String[]args)6{7inti=0;8intsum=0;910while(i<100)11{12i++;13sum=sum+......
  • 2023年7月杭州/北京/深圳DAMA-CDGP数据治理专家认证
    DAMA认证为数据管理专业人士提供职业目标晋升规划,彰显了职业发展里程碑及发展阶梯定义,帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力,促进开展工作实践应用及实际问题解决,形成企业所需的新数字经济下的核心职业竞争能力。DAMA是数据管理方面的认证,帮助数据从业者提升......
  • 2023-07-10 记录使用chrome浏览器点击内容搜索时跳转到了一个叫www.ibaixia.com的网站
    前言:猜测是chrome中毒了,或者就是网页被劫持了,每次搜索会跳转到www.ibaixia.com,然后在一瞬间又跳转到了百度搜索页。解决方案:在chrome打开chrome://settings/searchEngines,也就是打开设置,找到【网站搜索】一栏,在该栏中找到百度字样,然后打开它,如果是正确的www.baidu.com,那就不用......
  • 不忘初心 Windows10 22H2 19045.3155 x64 无更新 纯净 深度精简 2023.7.9
    注意此版不能更新补丁,支持人脸和指纹,此为深度精简版体积小、精简的比较多,适合软件不多的朋友使用,可以安装商店、以及其他UWP程序,可以登录微软账号。如有第三方软件打不开,请自行安装资源包里的微软常用运行库,为了保证稳定初心的系统全部都是离线精简和优化,非二次封装。系统纯净、流......
  • 2023ACM暑假训练day 11 动态规划
    目录DAY11动态规划训练情况简介题题题题DAY11动态规划训练地址:传送门训练情况简介2023-07-1009:30:17星期一早上:下午:晚上:题题意:思路:题题意:思路:题题意:思路:题题意:思路:......
  • SSO2.0 21-20230708
            ......