ABC334 参赛记录
__vector__ · · 个人记录
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
以下结论我认为很显然,不做解释。
如果
如果
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;
}