2025“钉耙编程”中国大学生算法设计春季联赛(10)4 7 9
关于我道心破碎,于是从新开始更新博客这件事(
1009 小塔的序列
猛地一看像类似 的一个 求最长子区间 使得里面每个出现的数字出现次数大于等于k 。
然后发现并不太像,然后 这个题很容易的想到这个题,肯定要把每个数质因数分解,然后求一个区间内值相乘,质因数个数是个偶数。
偶数,想到异或哈希,异或哈希把出现偶数次数的东西变成0.
我们把每个质因数赋个随机数,相乘表示成异或,那么我们要寻找一个最长的异或区间为0的,这个用前缀异或再加个map处理,
分解质因数和给质因数赋值可以在欧拉筛里面处理。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
#define pii pair<int, int>
#define all(a) a.begin(), a.end()
#define debug(x) cout << #x << " = " << x << endl
#define sz(a) ((int)a.size())
mt19937_64 rnd(time(nullptr));
const int mod = 998244353, N = 1e6 + 10, G = 3;
ll b[N];
ll c[N];
unordered_map<ll, ll> mp;
void solve()
{
int n;
scanf("%d", &n);
mp.clear();
int ans = 0;
int l, r;
int x;
ll y = 0;
for (int i = 1; i <= n; i++)
{
scanf("%d", &x);
y ^= b[x];
if (!mp[y])
{
mp[y] = i;
}
if (y == 0)
{
ans = i;
l = 1, r = i;
}
if (mp[y])
{
if (i - mp[y] > ans)
{
ans = i - mp[y];
l = mp[y] + 1;
r = i;
}
}
}
if (ans > 0)
PDF("%d %d\n", l, r);
else
printf("-1 -1\n");
}
ll pri[N];
ll pan[N];
int main()
{
int t = 1;
scanf("%d", &t);
int cnt = 0;
for (int i = 2; i <= 1e6; i++)
{
if (!pan[i])
{
b[i] = rnd();
pri[++cnt] = i;
}
for (int j = 1; j <= cnt && (long long)pri[j] * i <= 1e6; j++)
{
pan[i * pri[j]]++;
b[i * pri[j]] = b[i] ^ b[pri[j]];
if (i % pri[j] == 0)
break;
}
}
while (t--)
{
solve();
}
return 0;
}
1004 小塔的随机数
\(n\)和\(m\)都很小,尝试了几个数发现,如果按他给的区间整体来算发现无从下手,但是因为这个题很小的\(n,m\)可以跑个\(n*m*n\)的复杂度,我们可以思考用贡献求解的可能性。
设\(f[i][j]\)是\(i\),\(j\)是一个逆序的概率
发现 每一次随机化l r ,如果
- \({r>=i>=l \ and \ r<=j<=i}\) 时,\(f[i][j]=1/2\)
- \(r>=i>=l\)时 \(f[i][j]=(\sum_{k=l}^{r} f[k][j])/(r-l+1)\)
- \(r>=j>=l\)时 \(f[i][j]=(\sum_{k=l}^{r} f[i][k])/(r-l+1)\)
最后统计\(f[i][j]\)即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
#define pii pair<int, int>
#define all(a) a.begin(), a.end()
#define debug(x) cout << #x << " = " << x << endl
#define sz(a) ((int)a.size())
mt19937_64 rnd(time(nullptr));
const int mod = 1e9 + 7, N = 1e5 + 10, G = 3;
ll fastmi(ll base, ll power)
{
ll ans = 1;
base = base % mod;
while (power)
{
if (power & 1)
{
ans = ans * base % mod;
}
base = base * base % mod;
power >>= 1;
}
return ans;
}
ll dao[N];
void solve()
{
ll n, m;
cin >> n >> m;
vector<vector<ll>> f(n + 1, vector<ll>(n + 1, 0));
for (int _ = 1; _ <= m; _++)
{
int l, r;
cin >> l >> r;
vector<ll> fl(n + 1, 0);
for (int i = 1; i < l; i++)
{
for (int j = l; j <= r; j++)
fl[i] = (fl[i] + f[i][j]) % mod;
fl[i] = fl[i] * dao[r - l + 1] % mod;
} // 左边不在 右边在
vector<ll> fr(n + 1, 0);
for (int j = r + 1; j <= n; j++)
{
for (int i = l; i <= r; i++)
fr[j] = (fr[j] + f[i][j]) % mod;
fr[j] = fr[j] * dao[r - l + 1] % mod;
}
for (int i = 1; i <= n; i++)
for (int j = i + 1; j <= n; j++)
{
if (i >= l && i <= r && j >= l && j <= r)
f[i][j] = dao[2];
else if (i >= l && i <= r)
f[i][j] = fr[j];
else if (j >= l && j <= r)
f[i][j] = fl[i];
}
}
ll ans = 0;
for (int i = 1; i <= n; i++)
for (int j = i + 1; j <= n; j++)
ans = (ans + f[i][j]) % mod;
cout << ans << '\n';
}
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
for (int i = 1; i <= 500; i++)
{
dao[i] = fastmi(i, mod - 2);
}
while (t--)
{
solve();
}
return 0;
}
1007 小塔的魔法树
发现数据很小,然后我们可以跑一个n*m的时间复杂度
每个点的子树有m种取值,有1种转移可以考虑是一个DFS序上DP
把树搞成dfs序,
dp[i][j]表示位于dfs序i,能得到的魔力值时j的方案数
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
#define pii pair<int, int>
#define all(a) a.begin(), a.end()
#define debug(x) cout << #x << " = " << x << endl
#define sz(a) ((int)a.size())
// mt19937_64 rnd(time(nullptr));
const int mod = 1e9 + 7, N = 5e3 + 10, G = 3;
vector<int> edge[N];
void solve()
{
ll n, m;
cin >> n >> m;
vector<ll> a(n + 1);
for (int i = 1; i <= n; ++i)
cin >> a[i];
for (int i = 1; i < n; ++i)
{
int u, v;
cin >> u >> v;
edge[u].pb(v);
edge[v].pb(u);
}
vector<int> dfn(n + 2);
vector<int> dfn_ma(n + 2);
int cnt = 0;
auto dfs = [&](auto self, int u, int father) -> void
{
int now = ++cnt;
dfn[now] = u;
for (auto it : edge[u])
{
if (it == father)
continue;
self(self, it, u);
}
dfn_ma[now] = cnt + 1;
edge[u].clear();
};
dfs(dfs, 1, 0);
vector<vector<ll>> f(n + 2, vector<ll>(m + 1));
f[1][0] = 1;
for (int i = 1; i <= n; ++i)
{
for (int j = 0; j <= m - a[dfn[i]]; ++j)
{
f[i + 1][j + a[dfn[i]]] = f[i + 1][j + a[dfn[i]]] + f[i][j] % mod;
}
for (int j = 0; j <= m; ++j)
{
f[dfn_ma[i]][j] = (f[dfn_ma[i]][j] + f[i][j]) % mod;
}
}
ll ans = 0;
for (int i = 0; i <= m; i++)
ans = ans + f[n + 1][i] % mod;
cout << (ans + mod - 1) % mod << '\n';
}
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}

浙公网安备 33010602011771号