Logo __vector__ 的博客

博客

ABC334 参赛记录

...
__vector__
2025-12-01 12:55:58

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2023-12-23 22:25:15

md,G 题会做但是没调出来。

B

我认为解释不如直接看代码

 cin>>a>>m>>l>>r;
 if(a<l)
 {
    printf("%lld\n",calc(r)-calc(l-1));
 }
 else if(a>=l&&a<=r)
 {
     printf("%lld\n",(a-l)\/m+1+(r-a)\/m);
 }
 else
 {
     printf("%lld\n",calc2(l)-calc2(r+1));
 }  

C

以下结论我认为很显然,不做解释。

如果 $n$ 是偶数,那么排序,然后贪心地 $(1,2)$ 一对,$(3,4)$ 一对 $\cdots \cdots$

如果 $n$ 是奇数,那么枚举要删的点,经过预处理可以 $O(1)$ 计算得出删除每个点之后的答案。

D

纯纯前缀和二分板子。

E

先预处理连通块,然后枚举每个点,看把他涂成绿色的连通块个数,思想简单就是写起来麻烦。

F

暂时不会。

G

稍微修改一下求割点的算法,使其标记上它所连接的连通块数量,这个稍微思考一下就能想出来。

#include <bits\/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
const int maxm = 8e6 + 5;
int n, m;
int id(int i, int j)
{
    return (i - 1) * m + j;
}
int head[maxn];
struct EDGE
{
    int to, nxt;
} edge[maxm << 1];
int cnt = 1;
typedef long long ll;
const ll mod = 998244353;
ll qpow(ll a, ll b)
{
    ll ret = 1;
    while (b)
    {
        if (b & 1)
            ret = ret * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ret;
}
ll inv(ll a)
{
    return qpow(a, mod - 2);
}
void add(int u, int to)
{
    edge[++cnt].to = to;
    edge[cnt].nxt = head[u];
    head[u] = cnt;
}
int dfn[maxn];
int low[maxn];
int cut[maxn];
int ids; \/\/ 时间戳
void print(int x)
{
    int lie=x%m;
    if(lie==0)lie=m;
    printf("%d %d\n",(x-1)\/m+1,lie);
}
void tarjan(int u, int fa)
{
    dfn[u] = low[u] = ++ids;
    register int child = 0; \/\/ 子树
    for (int i = head[u]; i; i = edge[i].nxt)
    {
        register int to = edge[i].to;
        if (!dfn[to])
        { \/\/ 尚未访问过
            tarjan(to, fa);
            low[u] = min(low[u], low[to]);
            if (low[to] >= dfn[u] && u != fa) \/\/ 需要经过u访问更早的祖先
            {
                cut[u]++;
            }
            if (u == fa) \/\/ 如果是根节点
            {
                child++; \/\/ 子树++
            }
        }
        low[u] = min(low[u], dfn[to]); \/\/ 没有父子关系的话,那么按普通边计算,更新u
    }
    if (child >= 2 && u == fa) \/\/ 这样根节点也是割点,因为删除它就会有两棵蒲通的树不连通
    {
        cut[u] = child-1;
    }
   \/\/ printf("u = ",u);
   \/\/ print(u);
   \/\/ printf("cut = %d\n",cut[u]);
}
char s[1005][1005];
bool chk(int i, int j)
{
    if (s[i][j] != '#')
        return 0;
    if (i < 1 || i > n)
        return 0;
    if (j < 1 || j > m)
        return 0;
    return 1;
}
bool td[1000005];
void dfs(int u)
{
    td[u] = 1;
    for (int i = head[u]; i; i = edge[i].nxt)
    {
        int to = edge[i].to;
        if (!td[to])
            dfs(to);
    }
}
int ltkcnt;
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
    {
        scanf("%s", s[i] + 1);
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            if (chk(i, j))
            {
                if (chk(i - 1, j))
                {
                    add(id(i - 1, j), id(i, j));
                    add(id(i, j), id(i - 1, j));
                }
                if (chk(i + 1, j))
                {
                    add(id(i + 1, j), id(i, j));
                    add(id(i, j), id(i + 1, j));
                }
                if (chk(i, j - 1))
                {
                    add(id(i, j - 1), id(i, j));
                    add(id(i, j), id(i, j - 1));
                }
                if (chk(i, j + 1))
                {
                    add(id(i, j + 1), id(i, j));
                    add(id(i, j), id(i, j + 1));
                }
            }
        }
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            if (s[i][j] == '#' && !dfn[id(i, j)])
            {
                tarjan(id(i, j), id(i, j));
            }
            if (s[i][j] == '#' && !td[id(i, j)])
            {
                dfs(id(i, j));
                ltkcnt++;
            }
        }
    }
  \/\/  printf("ltkcnt = %d\n", ltkcnt);
    ll ans = 0;
    ll ansct = 0;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            if (s[i][j] != '.')
            {
                ansct++;
                bool ok=0;
                ok|=(s[i-1][j]=='#');
                ok|=(s[i][j-1]=='#');
                ok|=(s[i+1][j]=='#');
                ok|=(s[i][j+1]=='#');
                if(!ok)ans+=ltkcnt-1;
                else ans += (ltkcnt + max(0, cut[id(i, j)]));
            \/\/    printf("%d %d %d\n", i, j, (ltkcnt + cut[id(i, j)]));
                ans %= mod;
            }
        }
    }
    ans *= inv(ansct);
    printf("%lld", ans % mod);
    return 0;
}  

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。