msc
题意
给定一张
思路
与 CF888G 相似。将所有点的权插进一棵 01 Trie 中,若两点间有边,则这条边权的首位
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN=220000;
const int MAXM=13200000;
const ll INF=2E18;
struct Trie
{
int nxt[MAXM][2];
int cnt, root;
inline void init()
{
cnt=0; root=++cnt;
memset(nxt, 0, sizeof nxt);
}
void insert(ll x)
{
for (int i=59, p=root; i>=0; i--)
{
int t=x>>i&1;
if (!nxt[p][t]) nxt[p][t]=++cnt;
p=nxt[p][t];
}
}
int find()
{
int p=root;
while (p)
{
if (nxt[p][0]&&nxt[p][1]) return p;
if (nxt[p][0]) p=nxt[p][0];
else p=nxt[p][1];
}
return 0;
}
ll dfs(int u, int v, ll w)
{
ll r=INF;
if (nxt[u][0])
if (nxt[v][0]) r=min(r, dfs(nxt[u][0], nxt[v][0], w<<1));
else r=min(r, dfs(nxt[u][0], nxt[v][1], w<<1|1));
if (nxt[u][1])
if (nxt[v][1]) r=min(r, dfs(nxt[u][1], nxt[v][1], w<<1));
else r=min(r, dfs(nxt[u][1], nxt[v][0], w<<1|1));
return r==INF?w:r;
}
} trie;
int main()
{
// freopen("msc.in", "r", stdin);
// freopen("msc.out", "w", stdout);
int n;
scanf("%d", &n);
trie.init();
for (int i=1; i<=n; i++)
{
ll x; scanf("%lld", &x);
trie.insert(x);
}
int p=trie.find();
if (!p) puts("0");
else printf("%lld\n", trie.dfs(trie.nxt[p][0], trie.nxt[p][1], 1));
return 0;
}
across
题意
一个图有
思路
从每个节点走到它自己都有两种方式:
- 一直不走通向
0 的边,直到走回原点 - 先随便走若干次,再跳到
0 号节点,从它走到原点
对于第一种方式,可以考虑倍增求出每个点走
代码
#include <cstdio>
#include <cstring>
const int MAXN=1100000;
const int MOD=998244353;
int n, m;
int x[MAXN], y[MAXN];
int ans[MAXN];
int qpow(int n, int k)
{
int r=1;
while (k)
{
if (k&1) r=1ll*r*n%MOD;
n=1ll*n*n%MOD; k>>=1;
}
return r;
}
void mul(int* a, int* b, int* c)
{
static int t[MAXN];
for (int i=1; i<=n; i++) t[i]=b[a[i]];
memcpy(c, t, sizeof t);
}
void qpow(int* a, int* b, int k)
{
static int t[MAXN];
memcpy(t, a, sizeof t);
for (int i=1; i<=n; i++) b[i]=i;
while (k)
{
if (k&1) mul(b, t, b);
mul(t, t, t); k>>=1;
}
}
int main()
{
// freopen("across.in", "r", stdin);
// freopen("across.out", "w", stdout);
scanf("%d%d", &n, &m);
for (int i=0; i<=n; i++) scanf("%d", &x[i]);
for (int i=0, p=0; i<m; i++, p=x[p])
ans[p]=(ans[p]+qpow(2, m-i-1))%MOD;
if (m==0) ans[0]=1;
qpow(x, y, m);
for (int i=1; i<=n; i++)
if (y[i]==i) ans[i]=(ans[i]+1)%MOD;
for (int i=0; i<=n; i++) printf("%d ", ans[i]);
putchar('\n');
return 0;
}
count
题意
给出一棵
思路
动态 DP 。(并不会)