A 牛牛的mex运算
一.题目大意
给出
个数
,
次询问,每次给出
并询问
.
且
互异.
二.分析
赛时用的莫队,看题解才发现自己写麻烦了.
根据题目条件不难得
是
的一个排列.
因此
.
三.代码实现
1. 莫队
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int M = (int)1e5;
const int N = (int)5e5;
const int inf = 0x3f3f3f3f;
const ll mod = (ll)998244353;
const double eps = 1e-3;
int n, a[M + 5];
int q, block;
struct node
{
int l, r, id, bl;
bool operator< (const node& b)const
{
if(bl != b.bl) return bl < b.bl;
return r < b.r;
}
}s[M + 5];
int cur, ans[M + 5];
int cnt[M + 5];
void add(int x)
{
++cnt[a[x]];
while(cnt[cur]) ++cur;
}
void sub(int x)
{
--cnt[a[x]];
if(!cnt[a[x]]) cur = min(cur, a[x]);
}
int main()
{
// freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
scanf("%d %d", &n, &q); block = (int)sqrt(n);
for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
for(int i = 1; i <= q; ++i) scanf("%d %d", &s[i].l, &s[i].r), s[i].id = i, s[i].bl = s[i].l / block;
sort(s + 1, s + q + 1);
int l = 1, r = 0;
for(int i = 1; i <= q; ++i)
{
while(r < s[i].r) ++r, add(r);
while(r > s[i].r) sub(r), --r;
while(l < s[i].l) sub(l), ++l;
while(l > s[i].l) --l, add(l);
ans[s[i].id] = cur;
}
for(int i = 1; i <= q; ++i) printf("%d\n", ans[i]);
return 0;
} 2. 简单操作
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int M = (int)1e5;
const int N = (int)5e5;
const int inf = 0x3f3f3f3f;
const ll mod = (ll)998244353;
const double eps = 1e-3;
int n, q, a[M + 5];
int pre[M + 5], suf[M + 5];
int main()
{
// freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
scanf("%d %d", &n, &q);
for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
pre[0] = n; for(int i = 1; i <= n; ++i) pre[i] = min(pre[i - 1], a[i]);
suf[n + 1] = n; for(int i = n; i >= 1; --i) suf[i] = min(suf[i + 1], a[i]);
int l, r;
while(q--)
{
scanf("%d %d", &l, &r);
printf("%d\n", min(pre[l - 1], suf[r + 1]));
}
return 0;
} B 牛牛的算术
一.题目大意
T组询问,每组询问给出
,求
二.分析
化简可得
.
很容易想到当
大于某个值时,答案恒为 0. (打表可得当
时,答案为 0.)
那么直接搞就完事惹.
三.代码实现
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int M = (int)1e5;
const int N = (int)1e5;
const int inf = 0x3f3f3f3f;
const ll mod = (ll)199999;
const double eps = 1e-3;
ll quick(ll a, ll b, ll p = mod)
{
ll s = 1;
while(b)
{
if(b & 1) s = s * a % p;
a = a * a % p;
b >>= 1;
}
return s;
}
ll inv(ll n, ll p = mod)
{
return quick(n, p - 2, p);
}
ll cal(int n)
{
ll s = 0;
s += inv(8) % mod * n % mod * n % mod * n % mod * n % mod * n % mod; s %= mod;
s += 5 % mod * inv(12) % mod * n % mod * n % mod * n % mod * n % mod; s %= mod;
s += 3 % mod * inv(8) % mod * n % mod * n % mod * n % mod; s %= mod;
s += inv(12) % mod * n % mod * n % mod; s %= mod;
return s;
}
char s[M + 5];
ll f[M + 5];
void init()
{
f[0] = 1;
for(int i = 1; i <= 100000; ++i)
{
f[i] = f[i - 1] * cal(i) % mod;
}
f[0] = 0;
}
void work()
{
scanf("%s", s + 1);
int len = strlen(s + 1);
if(len >= 6)
{
printf("0\n");
return;
}
int n = 0;
for(int i = 1; i <= len; ++i) n = n * 10 + s[i] - '0';
printf("%lld\n", f[n]);
}
int main()
{
// freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
init();
int T; scanf("%d", &T);
while(T--) work();
return 0;
} C 牛牛的无向图
一.题目大意
给出
个点
条边的无向图,每条边有权值
.
定义一条路径的权值为这条路径上边权最大的边的权值.
定义
为
到
的所有路径中权值最小的路径的权值.
次询问,每次询问给出
,求
对
次答案异或一遍并输出.
.
二.分析
很容易想到对
和
排序,这样可以保证答案不降.
因此,对于处在
的边
,我们只需要统计有多个新点对产生.
不难(用)证明,按照
算法步骤,
一定是连通块
所有点
与连通块
所有点
的
.
详见代码.
三.代码实现
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int M = (int)1e6;
const int N = (int)5e5;
const int inf = 0x3f3f3f3f;
const ll mod = (ll)998244353;
const double eps = 1e-3;
struct node
{
int cat;
int u, v, w;
bool operator< (const node& b)const
{
if(w != b.w) return w < b.w;
return cat < b.cat;
}
}s[M + 5];
unsigned int SA, SB, SC; int n, m, q, LIM;
unsigned int rng61(){
SA ^= SA << 16;
SA ^= SA >> 5;
SA ^= SA << 1;
unsigned int t = SA;
SA = SB;
SB = SC;
SC ^= t ^ SA;
return SC;
}
void gen(){
scanf("%d%d%d%u%u%u%d", &n, &m, &q, &SA, &SB, &SC, &LIM);
for(int i = 1; i <= m; i++){
s[i].u = rng61() % n + 1;
s[i].v = rng61() % n + 1;
s[i].w = rng61() % LIM;
s[i].cat = 1;
}
for(int i = 1; i <= q; i++){
s[i + m].w = rng61() % LIM;
s[i + m].cat = 2;
}
}
int fa[M + 5], sz[M + 5];
int tofind(int x)
{
if(x == fa[x]) return x;
return fa[x] = tofind(fa[x]);
}
int main()
{
// freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
gen();
sort(s + 1, s + m + q + 1);
for(int i = 1; i <= n; ++i) fa[i] = i, sz[i] = 1;
ll ans = 0, cur = 0;
for(int i = 1, u, v; i <= m + q; ++i)
{
if(s[i].cat == 1)
{
u = s[i].u, v = s[i].v;
u = tofind(u), v = tofind(v);
if(u == v) continue;
cur += sz[u] * sz[v];
fa[u] = v, sz[v] += sz[u];
}
else ans ^= cur;
}
printf("%lld\n", ans);
return 0;
} D 牛牛的粉丝
一.题目大意
有一个环,长度为
,环上每个位置上有
个人.
先进行
次活动,每次活动每个人有
的概率按顺时针方向走一个单位,
的概率按逆时针方向走一个单位,
的概率待在原地.
问
次活动后,每个位置上人数的期望.
.
二.分析
记
为第
次活动结束后,
号位置人数的期望.
易得
.
由于
最大是
,我们用矩阵快速幂优化递推式. 即:
可这样时间复杂度是
,妥妥的 TLE...
观察到系数矩阵是循环矩阵,而循环矩阵有两个特点:
1.循环矩阵对加法和乘法封闭.
2.循环矩阵某一行或某一***定,则循环矩阵确定.
根据上述两条性质,我们则可把时间复杂度优化到
.
三.代码实现
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int M = (int)5e2;
const int N = (int)5e5;
const int inf = 0x3f3f3f3f;
const ll mod = (ll)998244353;
const double eps = 1e-3;
int n, a, b, c, s; ll k, p1, p2, p3;
struct Matrix
{
ll D[M + 5][M + 5];
}A, B, S, C;
ll quick(ll a, ll b, ll p = mod)
{
ll s = 1;
while(b)
{
if(b & 1) s = s * a % p;
a = a * a % p;
b >>= 1;
}
return s;
}
ll inv(ll n, ll p = mod)
{
return quick(n, p - 2, p);
}
void work()
{
S = B; --k;
while(k)
{
if(k & 1)
{
for(int i = 0; i < n; ++i) C.D[i][0] = 0;
for(int i = 0; i < n; ++i) for(int j = 0; j < n; ++j) C.D[i][0] = (C.D[i][0] + S.D[i][j] * B.D[j][0] % mod) % mod;
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < n; ++j)
{
C.D[j][(j - i + n) % n] = C.D[i][0];
}
}
memcpy(S.D, C.D, sizeof(C.D));
}
{
for(int i = 0; i < n; ++i) C.D[i][0] = 0;
for(int i = 0; i < n; ++i) for(int j = 0; j < n; ++j) C.D[i][0] = (C.D[i][0] + B.D[i][j] * B.D[j][0] % mod) % mod;
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < n; ++j)
{
C.D[j][(j - i + n) % n] = C.D[i][0];
}
}
memcpy(B.D, C.D, sizeof(C.D));
}
k >>= 1;
}
for(int i = 0; i < n; ++i) C.D[0][i] = 0;
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < n; ++j)
{
C.D[0][i] = (C.D[0][i] + A.D[0][j] * S.D[j][i]) % mod;
}
}
}
int main()
{
// freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
scanf("%d %lld", &n, &k);
scanf("%d %d %d", &a, &b, &c);
s = a + b + c;
p1 = a * inv(s) % mod, p2 = b * inv(s) % mod, p3 = c * inv(s) % mod;
memset(A.D, 0, sizeof(A.D));
memset(B.D, 0, sizeof(B.D));
for(int i = 0; i < n; ++i) scanf("%lld", &A.D[0][i]);
if(k == 0)
{
for(int i = 0; i < n; ++i) printf("%lld%c", A.D[0][i], i == n - 1 ? '\n' : ' ');
return 0;
}
for(int i = 0; i < n; ++i)
{
B.D[(i - 1 + n) % n][i] = p1;
B.D[(i + 1) % n][i] = p2;
B.D[i][i] = p3;
}
work();
for(int i = 0; i < n; ++i) printf("%lld%c", C.D[0][i], i == n - 1 ? '\n' : ' ');
return 0;
} 
京公网安备 11010502036488号