2023武汉联训
2023省选武汉联测1
算是 ?
大佬好多,我好菜
A. 递归函数
不难发现答案至于第 列有关
由于我们只关心指数,所以把乘法变成加法
每个数的贡献就是一个组合数的形式
然后不太会了
学到两种做法,一种是把这个贡献看成多项式拉格朗日插值
另一种是维护一行的值,用矩阵进行转移
枚举 每次有 的贡献
转移只有 特殊(有多的一个贡献)
于是求出 的矩阵然后快速幂,处理一下边界即可
对于 取较大的质因数
对于 把模数乘 最后直接除掉即可
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48);c = getchar();}while(isdigit(c));
return x;
}
ull mod = 998444353;
int n, m, b, invm;
struct matrix{
ull a[17][17];
matrix(){memset(a, 0, sizeof(a));}
void clear(){memset(a, 0, sizeof(a));}
friend matrix operator *(const matrix &x, const matrix &y){
matrix res;
for(int i = 0; i <= m; ++i)
for(int k = 0; k <= m; ++k)
if(x.a[i][k])
for(int j = 0; j <= m; ++j)
res.a[i][j] = (res.a[i][j] + x.a[i][k] * y.a[k][j]) % mod;
return res;
}
};
matrix qpow(matrix x, int y){
matrix res;
for(int i = 0; i <= m; ++i)res.a[i][i] = 1;
for(; y; y >>= 1, x = x * x)if(y & 1)res = res * x;
return res;
}
int qpow(int x, int y){
int ans = 1;
for(; y; y >>= 1, x = 1ll * x * x % mod)if(y & 1)ans = 1ll * ans * x % mod;
return ans;
}
ull calc(int p){
ull res = 0;
for(int a = p; a <= n; a *= p){
int x = n / a, y = n % a;
matrix tmp, tr;
for(int i = 1; i <= m; ++i)
for(int j = i; j <= m; ++j)
tmp.a[i][j] = 1;
tmp.a[0][0] = 1; tr = qpow(tmp, a - 1);
for(int i = 1; i <= m; ++i)tmp.a[0][i] = 1;
tr = qpow(tr * tmp, x);
for(int i = 1; i <= m; ++i)tmp.a[0][i] = 0;
tr = tr * qpow(tmp, y);
res = (res + tr.a[0][m]) % mod;
}
return res;
}
int main(){
freopen("function.in","r",stdin);
freopen("function.out","w",stdout);
n = read(), m = read(), b = read();
invm = 1; for(int i = 2; i <= m; ++i)invm = 1ll * invm * qpow(i, mod - 2) % mod;
ull ans;
switch(b){
case 2: ans = calc(2); break;
case 3: ans = calc(3); break;
case 4: mod <<= 1; ans = calc(2) / 2; break;
case 5: ans = calc(5); break;
case 6: ans = calc(3); break;
case 7: ans = calc(7); break;
case 8: mod *= 3; ans = calc(2) / 3; break;
case 9: mod <<= 1; ans = calc(3) / 2; break;
case 10: ans = calc(5); break;
}
printf("%d\n",ans);
return 0;
}
B. 火力规划
只考虑一个方向,其他方向可以旋转,一样处理
一个士兵的贡献是一个等腰三角形,斜边在对角线上
斜边的限制可以用横纵坐标之和/差表示
于是用二维树状数组可以维护
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48);c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 5e3 + 55;
int n, q;
struct op{int opt, dir, x, y, r;}d[maxn * 20];
struct BIT{
int t[maxn][maxn * 2];
int lowbit(int x){return x & -x;}
void add(int x, int y, int val){
for(int a = x; a <= n; a += lowbit(a))
for(int b = y; b <= n + n; b += lowbit(b))
t[a][b] += val;
}
int query(int x, int y){
int res = 0;
for(int a = x; a; a -= lowbit(a))
for(int b = y; b; b -= lowbit(b))
res += t[a][b];
return res;
}
void clear(){memset(t, 0, sizeof(t));}
}T1, T2;
int ans[maxn * 20];
int main(){
freopen("planning.in","r",stdin);
freopen("planning.out","w",stdout);
n = read(), q = read();
for(int i = 1; i <= q; ++i){
d[i].opt = read();
if(d[i].opt & 1){
d[i].dir = read(), d[i].x = read(), d[i].y = read(), d[i].r = read();
if(d[i].dir == 1){
d[i].dir = 3;
}else if(d[i].dir == 2){
d[i].dir = 4;
}else if(d[i].dir == 3){
d[i].dir = 2;
}else if(d[i].dir == 4){
d[i].dir = 1;
}
}else{d[i].x = read(), d[i].y = read();}
}
for(int dir = 1; dir <= 4; ++dir){
T1.clear(), T2.clear();
for(int i = 1; i <= q; ++i)if(d[i].opt == 1 && d[i].dir == dir){
int x = d[i].x, y = d[i].y, r = d[i].r;
T1.add(x - r, x + y - r, 1);
T1.add(x + 1, x + y - r, -1);
T2.add(x - r, y + 1, -1);
T2.add(x + 1, y + 1, 1);
}else if(d[i].opt == 2){
int x = d[i].x, y = d[i].y;
ans[i] += T1.query(x, x + y) + T2.query(x, y);
}
for(int i = 1; i <= q; ++i)swap(d[i].x, d[i].y), d[i].x = n + 1 - d[i].x;
}
for(int i = 1; i <= q; ++i)if(d[i].opt == 2)printf("%d\n",ans[i]);
return 0;
}
C. 再生核希尔伯特空间
用 自动机或者 都能做,做法类似
核心在于根号分治
口胡一下 自动机, 代码没打完
考虑 的,考虑其每个结点会贡献 树上到根的路径中经过的其他串的结尾,
修改该串结点的权值为 , 对整棵树做 求每个点的子树和即可
对于 的,反过来考虑祖先对他的贡献,发现就是在每个点查询到根路径上颜色在 之间的点有多少
离线下来差分搞一下
code
#include<bits/stdc++.h>
using namespace std;
namespace mycode{
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48);c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 5e5 + 55;
char s[maxn];
int n, q, ed[maxn], len[maxn], B, m;
struct AC{
int ch[maxn][26], fa[maxn], fail[maxn], cnt = 1;
int insert(int len){
int now = 1;
for(int i = 1; i <= len; ++i){
if(!ch[now][s[i] - 'a'])fa[ch[now][s[i] - 'a'] = ++cnt] = now;
now = ch[now][s[i] - 'a'];
}
return now;
}
queue<int>q;
vector<int>g[maxn];
void build(){
for(int i = 0; i < 26; ++i)if(ch[1][i])q.push(ch[1][i]), fail[ch[1][i]] = 1;
else ch[1][i] = 1;
while(!q.empty()){
int x = q.front(); q.pop();
for(int i = 0; i < 26; ++i)
if(ch[x][i])q.push(ch[x][i]), fail[ch[x][i]] = ch[fail[x]][i];
else ch[x][i] = ch[fail[x]][i];
}
}
int val[maxn], sum[maxn];
void add(int pos){
while(pos){
++val[pos];
pos = fa[pos];
}
}
void dfs(int x){
sum[x] = val[x];
for(int v : g[x])dfs(v), sum[x] += sum[v];
}
void modify(int x){
}
int query(int x){
}
}A;
struct node{
int op, pos;
friend bool operator < (const node &x, const node &y){
return x.pos < y.pos;
}
};
int ans[maxn];
vector<node>vec[maxn];
int main(){
// freopen("rkhs.in","r",stdin);
// freopen("rkhs.out","w",stdout);
n = read(), q = read();
for(int i = 1; i <= n; ++i){
scanf("%s",s + 1); len[i] = strlen(s + 1);
ed[i] = A.insert(len[i]); m += len[i];
}
B = sqrt(m);
for(int i = 1; i <= q; ++i){
int a = read() - 1, b = read(), k = read();
node l; l.pos = k; l.op = -1;
node r; r.pos = k; r.op = 1;
vec[a].push_back(l);
vec[b].push_back(r);
}
A.build();
for(int i = 1; i <= n; ++i){
if(len[i] >= B)A.add(ed[i]), A.dfs(1);
for(node x : vec[i])ans[x.pos] += x.op * A.sum[ed[x.pos]];
}
for(int i = 1; i <= n; ++i){
if(len[i] < B)A.modify(ed[i]);
for(node x : vec[i])ans[x.pos] += x.op * A.query(ed[x.pos]);
}
return 0;
}
}
const int N = 1E5 + 10, S = 2e5 + 10, Q = 2E5 + 10;
using ll = long long;
struct acam {
#define fail(x) tr[x].fail
#define ch(x, p) tr[x].ch[p]
struct node {
int ch[26];
int fail;
} tr[S];
int root = 1, tot = 1;
int newnode() { return ++tot; }
int insert(string s) {
int u = root;
for (auto c : s) {
if (ch(u, c - 'a') == 0)
ch(u, c - 'a') = newnode();
u = ch(u, c - 'a');
}
return u;
}
vector<int> get_nds(string s) {
vector<int> ret;
ret.reserve(s.size());
int u = root;
for (auto c : s) {
u = ch(u, c - 'a');
assert(u);
ret.push_back(u);
}
return ret;
}
void get_fail() {
queue<int> q;
for (int i = 0; i < 26; ++i) {
if (ch(root, i))
fail(ch(root, i)) = root, q.push(ch(root, i));
else
ch(root, i) = root;
}
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = 0; i < 26; ++i) {
if (ch(u, i))
fail(ch(u, i)) = ch(fail(u), i), q.push(ch(u, i));
else
ch(u, i) = ch(fail(u), i);
}
}
}
} AC;
struct tree {
vector<int> e[S];
ll f[S];
void inse(int u, int v) { e[u].push_back(v); }
int dfn[S], dfe[S], tim;
void pre(int u) {
dfn[u] = ++tim;
for (int v : e[u]) {
pre(v);
}
dfe[u] = tim;
}
void dfs(int u) {
for (int v : e[u]) {
dfs(v);
f[u] += f[v];
}
}
} T;
int ds, db;
struct db_t {
ll tag[S];
int bel[S];
ll a[S];
int L[S], R[S];
void init(int len) {
ds = ceil(sqrt(len));
db = ceil(1.0 * len / ds);
for (int i = 1; i <= len; ++i) bel[i] = ceil(1.0 * i / ds);
for (int i = 1; i <= db; ++i) L[i] = (i - 1) * ds + 1, R[i] = i * ds;
}
void add(int l, int r) {
int bl = bel[l], br = bel[r];
if (bl == br) {
for (int i = l; i <= r; ++i) ++a[i];
return;
}
for (int i = l; i <= R[bl]; ++i) ++a[i];
for (int i = L[br]; i <= r; ++i) ++a[i];
for (int i = bl + 1; i <= br - 1; ++i) ++tag[i];
}
int query(int x) { return a[x] + tag[bel[x]]; }
} segt;
struct que_t {
int p, k, id, coef;
};
vector<que_t> sma, big;
ll ans[Q];
int edp[N];
int n, q;
string strs[N];
int bnd;
ll arr[N];
int main() {
freopen("rkhs.in", "r", stdin);
freopen("rkhs.out", "w", stdout);
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int sizsum = 0;
cin >> n >> q;
for (int i = 1; i <= n; ++i) {
cin >> strs[i];
edp[i] = AC.insert(strs[i]);
}
for (int i = 1; i <= n; ++i) sizsum += strs[i].length();
bnd = sqrt(sizsum);
AC.get_fail();
for (int i = 2; i <= AC.tot; ++i) T.inse(AC.fail(i), i);
T.pre(AC.root);
segt.init(AC.tot);
for (int i = 1; i <= q; ++i) {
int l, r, k;
cin >> l >> r >> k;
if (strs[k].size() <= bnd) {
sma.push_back({ l - 1, k, i, -1 });
sma.push_back({ r, k, i, 1 });
} else {
big.push_back({ l - 1, k, i, -1 });
big.push_back({ r, k, i, 1 });
}
}
sort(big.begin(), big.end(), [&](que_t a, que_t b) { return a.k < b.k; });
int nowid = -1;
for (auto it : big) {
if (it.k != nowid) {
nowid = it.k;
memset(arr, 0, sizeof(arr));
memset(T.f, 0, sizeof(T.f));
auto nds = AC.get_nds(strs[it.k]);
for (auto it : nds) {
T.f[it] = 1;
}
T.dfs(AC.root);
for (int i = 1; i <= n; ++i) arr[i] = T.f[edp[i]];
partial_sum(arr + 1, arr + 1 + n, arr + 1);
}
ll val = arr[it.p] * it.coef;
ans[it.id] += val;
}
sort(sma.begin(), sma.end(), [&](que_t a, que_t b) { return a.p < b.p; });
int rp = 0;
for (auto it : sma) {
while (rp < it.p) {
++rp;
int u = edp[rp];
segt.add(T.dfn[u], T.dfe[u]);
}
auto nds = AC.get_nds(strs[it.k]);
ll val = 0;
for (auto u : nds) {
val += segt.query(T.dfn[u]);
}
val *= it.coef;
ans[it.id] += val;
}
for (int i = 1; i <= q; ++i) {
cout << ans[i] << "\n";
}
cout << endl;
return 0;
}
2023省选武汉联测2
数据结构 () 专场
A. After God
神仙回滚莫队
首先很多位没用,离散化一下,可以把值域降到
每次处理左端点在一块的询问
向右扩展可以直接暴力做,均摊下来是 的(一个 只会在进位时贡献一次)
考虑如何快速维护向左扩展以及回滚操作
把值域按照当前块的值进行分块
维护每个块左端点开始 个数(直接用 压位)
再维护之后的连续的 的个数
考虑左侧的扩展,每一块至多向上贡献一个 , 那么进位产生的影响只会在 位和前缀 的位置产生影响
于是每次就可以在 的复杂度内完成左端点的操作了
下面的代码是直接压位的暴力。。。。。
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int read(){
int x = 0; char c = getchar(); bool f = false;
while(!isdigit(c))f = c == '-', c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return f ? -x : x;
}
const int maxn = 1e6 + 55;
int mx;
int n, m, a[maxn], tmp[maxn], p[maxn], bl[maxn], B;
int ans[maxn];
struct node{
int l, r, id;
friend bool operator < (const node &x, const node &y){return bl[x.l] == bl[y.l] ? x.r < y.r : x.l < y.l;}
}d[maxn];
int cnt, pop[maxn];
ull tub[maxn];
void add(int pos){
int x = a[pos], y = x >> 6;
ull las = tub[y];
tub[y] += (1ull << (x & 63));
cnt -= pop[y];
pop[y] = __builtin_popcountll(tub[y]);
cnt += pop[y];
if(((las & (1ull << 63)) == (1ull << 63)) && ((tub[y] & (1ull << 63)) == 0)){
++y;
do{
cnt -= pop[y]; ++tub[y];
pop[y] = __builtin_popcountll(tub[y]);
cnt += pop[y];
}while(tub[y] == 0 && (++y));
}
}
void del(int pos){
int x = a[pos], y = x >> 6;
ull las = tub[y];
tub[y] -= (1ull << (x & 63));
cnt -= pop[y];
pop[y] = __builtin_popcountll(tub[y]);
cnt += pop[y];
if(((las & (1ull << 63)) == 0) && ((tub[y] & (1ull << 63)) == (1ull << 63))){
++y;
do{
cnt -= pop[y]; --tub[y];
pop[y] = __builtin_popcountll(tub[y]);
cnt += pop[y];
}while((~tub[y] == 0) && (++y));
}
}
void solve(){
int l = d[1].l, r = d[1].l - 1;
for(int i = 1; i <= m; ++i){
while(l > d[i].l)--l, add(l);
while(r < d[i].r)++r, add(r);
while(l < d[i].l)del(l), ++l;
while(r > d[i].r)del(r), --r;
ans[d[i].id] = cnt;
}
}
bool cmp(int x, int y){return a[x] < a[y];}
int main(){
freopen("god.in","r",stdin);
freopen("god.out","w",stdout);
n = read(), m = read();
for(int i = 1; i <= n; ++i)a[i] = tmp[i] = read(), p[i] = i;
sort(tmp + 1, tmp + n + 1); sort(p + 1, p + n + 1, cmp);
for(int i = n; i > 1; --i)tmp[i] = tmp[i] - tmp[i - 1];
tmp[1] = 1;
for(int i = 2; i <= n; ++i)tmp[i] = min(tmp[i], 18);
for(int i = 2; i <= n; ++i)tmp[i] += tmp[i - 1];
for(int i = 1; i <= n; ++i)a[p[i]] = tmp[i];
mx = tmp[n] + 18;
B = pow(n, 0.5); for(int i = 1; i <= n; ++i)bl[i] = (i + B - 1) / B;
for(int i = 1; i <= m; ++i){
d[i].l = read(), d[i].r = read(); d[i].id = i;
}
sort(d + 1, d + m + 1);
solve();
for(int i = 1; i <= m; ++i)printf("%d\n",ans[i]);
return 0;
}
B. 魔法少女
神仙线段树
按照 分块
块内询问直接山海经
考虑块间
设 表示前一个块后 个数的后缀和
表示后一个块前 个数的前缀和
那么限制变成 的最大值
然后怎么维护一下。。。
C. 愚者之夜
分颜色处理,根号分治
对于出现次数小于根号的,枚举两个位置,查询区间最大最小值,得到当 满足一定条件时才会有贡献
那么变成了二维数点问题
对于出现次数大于根号的
用回滚莫队维护答案
2023省选武汉联测3
A. 回文串
可以发现如果两侧字符一样,则翻不翻转两侧是一样的
那么可以不停的去掉两侧相同的字符
发现剩下的两侧不同,那么翻转的区间一个端点必然是此时两个端点中的一个
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = (x * 10) + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 2e5 + 55, base1 = 29, base2 = 233, mod = 1e9 + 7;
int n, len;
char s[maxn], c[maxn];
ull bp1[maxn]; int bp2[maxn];
struct Hash{
ull h1; int h2;
Hash(){h1 = h2 = 0;}
Hash(ull x, int y){h1 = x; h2 = y;}
friend bool operator == (const Hash &x, const Hash &y){
return x.h1 == y.h1 && x.h2 == y.h2;
}
friend Hash operator + (const Hash &x, const Hash &y){
return Hash(x.h1 + y.h1, (x.h2 + y.h2) % mod);
}
Hash operator * (const int l){
return Hash(h1 * bp1[l], 1ll * h2 * bp2[l] % mod);
}
}pre[maxn], suf[maxn];
Hash get_pre(int l, int r){return Hash(pre[r].h1 - pre[l - 1].h1 * bp1[r - l + 1], (pre[r].h2 - 1ll * pre[l - 1].h2 * bp2[r - l + 1] % mod + mod) % mod);}
Hash get_suf(int l, int r){return Hash(suf[l].h1 - suf[r + 1].h1 * bp1[r - l + 1], (suf[l].h2 - 1ll * suf[r + 1].h2 * bp2[r - l + 1] % mod + mod) % mod);}
void sol(){
for(int i = 1; i <= len; ++i)pre[i] = Hash(pre[i - 1].h1 * base1 + (c[i] - 'a'), (1ll * pre[i - 1].h2 * base2 + (c[i] - 'a')) % mod);
suf[len + 1].h1 = suf[len + 1].h2 = 0;
for(int i = len; i >= 1; --i)suf[i] = Hash(suf[i + 1].h1 * base1 + (c[i] - 'a'), (1ll * suf[i + 1].h2 * base2 + (c[i] - 'a')) % mod);
}
void solve(){
n = read(); scanf("%s",s + 1);
int L = 1, R = n;
while(L <= R && s[L] == s[R])++L, --R;
if(L > R){printf("1 1\n");return;}
len = R - L + 1;
for(int i = L; i <= R; ++i)c[i - L + 1] = s[i];
sol();
for(int i = 1; i <= len; ++i){
int j = len - i;
if(get_suf(1, i) * j + get_pre(i + 1, len) == get_suf(i + 1, len) * i + get_pre(1, i)){
printf("%d %d\n",L, L + i - 1); return;
}
if(get_pre(1, j) * i + get_suf(j + 1, len) == get_pre(j + 1, len) * j + get_suf(1, j)){
printf("%d %d\n",j + L, R); return;
}
}
printf("-1 -1\n");
}
int main(){
// freopen("palindrome.in","r",stdin);
// freopen("palindrome.out","w",stdout);
bp1[0] = bp2[0] = 1;
for(int i = 1; i <= 1e5 + 5; ++i)bp1[i] = bp1[i - 1] * base1;
for(int i = 1; i <= 1e5 + 5; ++i)bp2[i] = 1ll * bp2[i - 1] * base2 % mod;
int t = read(); for(int i = 1; i <= t; ++i)solve();
return 0;
}
B. 国际象棋
特批 的
构造 的
更大的可以拆分成
code
#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = (x * 10) + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
struct node{
int a, b, c, d;
node(){}
node(int e, int f, int g, int h){a = e; b = f; c = g; d = h;}
node add(int x, int y){return node{a + x, b + y, c + x, d + y};}
node radd(int x, int y){return node{b + x, a + y, d + x, c + y};}
};
vector<node>tabe[7][7], ans;
void case24(int x, int y){
ans.push_back({x, y, x + 1, y + 2});
ans.push_back({x + 1, y, x, y + 2});
ans.push_back({x, y + 1, x + 1, y + 3});
ans.push_back({x + 1, y + 1, x, y + 3});
}
void case42(int x, int y){
ans.push_back({x, y, x + 2, y + 1});
ans.push_back({x, y + 1, x + 2, y});
ans.push_back({x + 1, y, x + 3, y + 1});
ans.push_back({x + 1, y + 1, x + 3, y});
}
void pre(){
tabe[3][3] = { { 1, 1, 3, 2 }, { 1, 2, 3, 3 }, { 1, 3, 2, 1 }, { 2, 3, 3, 1 } };
tabe[3][4] = { { 1, 1, 3, 2 }, { 1, 2, 2, 4 }, { 1, 3, 2, 1 }, { 1, 4, 3, 3 }, { 2, 2, 3, 4 }, { 2, 3, 3, 1 } };
tabe[3][5] = { { 1, 1, 3, 2 }, { 1, 2, 3, 1 }, { 1, 3, 2, 1 }, { 1, 4, 2, 2 }, { 1, 5, 3, 4 }, { 2, 3, 3, 5 }, { 2, 5, 3, 3 } };
tabe[3][6] = { { 1, 1, 3, 2 }, { 1, 2, 3, 1 }, { 1, 3, 2, 1 }, { 1, 4, 2, 2 }, { 1, 5, 2, 3 }, { 1, 6, 3, 5 }, { 2, 4, 3, 6 }, { 2, 5, 3, 3 }, { 2, 6, 3, 4 } };
tabe[4][5] = { { 1, 1, 3, 2 }, { 1, 2, 3, 1 }, { 1, 3, 2, 1 }, { 1, 4, 2, 2 }, { 1, 5, 2, 3 }, { 2, 4, 4, 5 }, { 2, 5, 4, 4 }, { 3, 3, 4, 1 }, { 3, 4, 4, 2 }, { 3, 5, 4, 3 } };
tabe[4][6] = { { 1, 1, 3, 2 }, { 1, 2, 3, 1 }, { 1, 3, 2, 1 }, { 1, 4, 2, 2 }, { 1, 5, 2, 3 }, { 1, 6, 2, 4 }, { 2, 5, 4, 6 }, { 2, 6, 4, 5 }, { 3, 3, 4, 1 }, { 3, 4, 4, 2 }, { 3, 5, 4, 3 }, { 3, 6, 4, 4 } };
tabe[5][5] = { { 1, 1, 3, 2 }, { 1, 2, 3, 1 }, { 1, 3, 2, 1 }, { 1, 4, 2, 2 }, { 1, 5, 2, 3 }, { 2, 4, 4, 5 }, { 2, 5, 3, 3 }, { 3, 4, 4, 2 }, { 3, 5, 5, 4 }, { 4, 1, 5, 3 }, { 4, 3, 5, 1 }, { 4, 4, 5, 2 } };
tabe[5][6] = { { 1, 1, 3, 2 }, { 1, 2, 3, 1 }, { 1, 3, 2, 1 }, { 1, 4, 2, 2 }, { 1, 5, 2, 3 }, { 1, 6, 2, 4 }, { 2, 5, 3, 3 }, { 2, 6, 4, 5 }, { 3, 4, 4, 2 }, { 3, 5, 5, 6 }, { 3, 6, 5, 5 }, { 4, 1, 5, 3 }, { 4, 3, 5, 1 }, { 4, 4, 5, 2 }, { 4, 6, 5, 4 } };
tabe[6][6] = { { 1, 1, 3, 2 }, { 1, 2, 3, 1 }, { 1, 3, 2, 1 }, { 1, 4, 2, 2 }, { 1, 5, 2, 3 }, { 1, 6, 2, 4 }, { 2, 5, 3, 3 }, { 2, 6, 3, 4 }, { 3, 5, 4, 3 }, { 3, 6, 5, 5 }, { 4, 1, 6, 2 }, { 4, 2, 6, 1 }, { 4, 4, 5, 2 }, { 4, 5, 5, 3 }, { 4, 6, 6, 5 }, { 5, 1, 6, 3 }, { 5, 4, 6, 6 }, { 5, 6, 6, 4 } };
}
int n, m;
void solve(int x, int y, int a, int b){
if(a == 4 && b == 4){case24(x + 1, y + 1); case24(x + 3, y + 1); return;}
if(a > b)for(auto v : tabe[b][a])ans.push_back(v.radd(x, y));
else for(auto v : tabe[a][b])ans.push_back(v.add(x, y));
}
void solve1(){
if(n == 1 || m == 1)return;
if(n == 2){
for(int i = 1; i <= m; i += 4)if(i + 3 <= m)case24(1, i);
if(m % 4 == 3){ans.push_back({1, m, 2, m - 2}); ans.push_back({1, m - 2, 2, m});}
}
else{
for(int i = 1; i <= n; i += 4)if(i + 3 <= n)case42(i, 1);
if(n % 4 == 3){ans.push_back({n, 1, n - 2, 2});ans.push_back({n, 2, n - 2, 1});}
}
}
void solve2(){
int rn = n % 4, rm = m % 4;
if(rn < 3) rn += 4;
if(rm < 3) rm += 4;
for(int i = 1; i + 3 <= n - rn; i += 4)
for(int j = 1; j + 3 <= m - rm; j += 4)
solve(i - 1, j - 1, 4, 4);
if(rm)for(int i = 1; i + 3 <= n - rn; i += 4)solve(i - 1, m - rm, 4, rm);
if(rn)for(int i = 1; i + 3 <= m - rm; i += 4)solve(n - rn, i - 1, rn, 4);
if(rn && rm)solve(n - rn, m - rm, rn, rm);
}
void solve(){
n = read(), m = read();
if(n < 3 || m < 3)solve1();
else solve2();
printf("%d\n",(int)ans.size());
for(auto x : ans){
printf("%d %d %d %d\n",x.a, x.b, x.c, x.d);
}
ans.clear();
}
int main(){
freopen("knight.in","r",stdin);
freopen("knight.out","w",stdout);
pre(); int t = read();
for(int i = 1; i <= t; ++i)solve();
return 0;
}
C. 嘉心糖
建补图,问题变成找最大独立集
给边定向,标号小的指向标号大的,
可以证明如果 无边 无边,则 无边
于是能证明答案为最长反链?
然后根据狄尔沃斯定理要求最小链覆盖
于是拆点,答案为
然后优化匈牙利算法
复杂度分析不会
参考https://www.cnblogs.com/whx1003/p/15597645.html
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = (x * 10) + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 5e5 + 55;
int n, m, deg[maxn], a[maxn], p[maxn];
int f[maxn];
int fa(int x){return f[x] == x ? x : f[x] = fa(f[x]);}
bool cmp(int x, int y){return deg[x] < deg[y];}
int ra[maxn], rb[maxn];
set<int, greater<int>>s;
set<int>del[maxn];
bool dfs(int x){
int find = x + 1;
while(find = fa(find), find <= n){
if(del[x].count(find)){++find; continue;}
else{
f[find] = find + 1;
if(!rb[find] || dfs(rb[find])){
ra[x] = find; rb[find] = x;
return true;
}
}
}
return false;
}
int main(){
freopen("sugar.in","r",stdin);
freopen("sugar.out","w",stdout);
n = read(), m = read();
for(int i = 1; i <= n; ++i)deg[i] = n - i, p[i] = a[i] = i;
for(int i = 1; i <= m; ++i){
int x = read();
del[min(a[x], a[x + 1])].insert(max(a[x], a[x + 1]));
--deg[min(a[x], a[x + 1])]; swap(a[x], a[x + 1]);
}
for(int i = 1; i <= n; ++i)s.insert(i);
sort(p + 1, p + n + 1, cmp);
int ans = 0;
for(int i = 1; i <= n; ++i){
int now = p[i];
if(deg[now] > ans)for(int v : s)
if(v > now && !del[now].count(v)){
ra[now] = v; rb[v] = now;
s.erase(v);
++ans;
break;
}
}
for(int i = 1; i <= n; ++i)if(!ra[i]){
for(int j = 1; j <= n + 1; ++j)f[j] = j;
ans += dfs(i);
}
printf("%d\n", n - ans);
return 0;
}
2023省选武汉联测4
A. 挑战NPC
虽然但是,直接BK能过
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
int read(){
int x = 0; bool f = false; char c = getchar();
while(!isdigit(c))f = c == '-', c = getchar();
do{x = (x * 10) + (c ^ 48); c = getchar();}while(isdigit(c));
return f ? -x : x;
}
const int maxn = 1e5 + 55;
int n, m, ans = 1;
struct node{int x, y;}d[maxn];
mt19937 rd((ull)&maxn);
ll sq(ll x){return x * x;}
ll dis2(const node &x, const node &y){return sq(x.x - y.x) + sq(x.y - y.y);}
vector<pii>e[maxn];
bool mp[205][205];
int p[maxn];
int id[205][205], dp[maxn];
void dfs(int si, int num){
if(si == 0){
if(num > ans)ans = num;
return;
}
for(int i = 1; i <= si; ++i){
if(si - i + 1 + num <= ans)return;
int now = id[num][i];
if(dp[now] + num <= ans)return;
int cnt = 0;
for(int j = i + 1; j <= si; ++j)
if(mp[now][id[num][j]])
id[num + 1][++cnt] = id[num][j];
dfs(cnt, num + 1);
}
}
void solve(){
ans = 0;
for(int i = n; i >= 1; --i){
int cnt = 0;
for(int j = i + 1; j <= n; ++j)
if(mp[i][j])id[1][++cnt] = j;
dfs(cnt, 1);
dp[i] = ans;
}
}
void add(int d){
for(pii v : e[d]){
mp[v.first][v.second] = true;
mp[v.second][v.first] = true;
}
shuffle(p + 1, p + n + 1, rd);
solve();
}
int main(){
freopen("challenge.in","r",stdin);
freopen("challenge.out","w",stdout);
n = read(); m = read();
for(int i = 1; i <= n; ++i)p[i] = i;
for(int i = 1; i <= n; ++i)d[i].x = read(), d[i].y = read();
for(int i = 1; i <= n; ++i)
for(int j = i + 1; j <= n; ++j){
ll d2 = dis2(d[i], d[j]);
int v = max((int)ceil(sqrt(d2)) - 5, 1);
while(1ll * v * v < d2)++v;
if(v <= m)e[v].push_back(pii(i, j));
}
for(int d = 0; d <= m; ++d){
if(e[d].size())add(d);
printf("%d ",ans);
}
printf("\n");
return 0;
}
B. 糖果大赛
类打表题
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = (x * 10) + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 205, mod = 998244353;
int n, a[maxn];
void sort_and_unique(vector<int>&x){
sort(x.begin(), x.end());
x.resize(unique(x.begin(), x.end()) - x.begin());
}
map<vector<int>, bool>mp;
bool dfs(vector<int>x){
sort_and_unique(x);
if(x.size() == 0)return true;
if(x == vector<int>{4, 8})return false;
if(x == vector<int>{1})return false;
if(x == vector<int>{2})return false;
for(auto v : x)if(v % 12)return true;
if(mp.count(x))return mp[x];
for(int s = 1; s <= x.back(); ++s){
vector<int>tmp;
for(int v : x)if(v % s)tmp.push_back(v % s);
if(dfs(tmp) == false)return mp[x] = true;
}
return mp[x] = false;
}
int calc(vector<int>x){
vector<int> f(1 << x.size(), 0); f[0] = 1;
for(int i = 1; i <= n; ++i){
vector <int> g(f.size(), 0);
for(int j = 0; j < x.size(); ++j)if(a[i] >= x[j]){
for(int s = 0; s < f.size(); ++s)if(f[s]){
(g[s | (1 << j)] += f[s]) %= mod;
}
}
f.swap(g);
}
return f.back();
}
int main(){
freopen("candy.in","r",stdin);
freopen("candy.out","w",stdout);
n = read();
for(int i = 1; i <= n; ++i)a[i] = read();
vector<vector<int>>ban;
ban.push_back(vector<int>{1});
ban.push_back(vector<int>{2});
ban.push_back(vector<int>{4, 8});
for(int s = 1; s < (1 << 16); ++s){
vector<int>tmp;
for(int i = 0; i <= 15; ++i)if(s >> i & 1)tmp.push_back((i + 1) * 12);
if(!dfs(tmp))ban.push_back(tmp);
}
int ans = 1;
for(int i = 1; i <= n; ++i)ans = 1ll * ans * a[i] % mod;
for(auto v : ban)ans = (ans + mod - calc(v)) % mod;
printf("%d", ans);
return 0;
}
C. 聚会
神奇贪心
code
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = (x * 10) + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
int n, m;
const int maxn = 3e5 + 55;
vector<pii>v[maxn];
ll a[maxn], b[maxn];
int p;
bool check(ll mid, ll val){
for(int i = 1; i <= n; ++i)b[i] = 0;
priority_queue<pii>q;
int s = 0;
for(int i = 1; i <= p; ++i){
for(auto x : v[i])if(x.first > p)q.push(x);
while(a[i] - s + val - s > mid){
if(q.empty())return false;
pii x = q.top(); q.pop();
int del = min(x.second, (a[i] + val - mid + 1) / 2 - s);
s += del; x.second -= del;
b[p + 1] -= del;
b[x.first] += del * 2;
if(x.second)q.push(x);
}
}
for(int i = p + 1; i <= n; ++i){
b[i] += b[i - 1];
if(a[i] + b[i] > mid)return false;
}
return true;
}
signed main(){
freopen("party.in","r",stdin);
freopen("party.out","w",stdout);
n = read(); m = read();
for(int i = 1; i <= m; ++i){
int l = read(), r = read(), x = read();
if(l > r)swap(l, r);
a[l] += x; a[r] -= x; v[l].push_back(pii(r, x));
}
for(int i = 1; i <= n; ++i)a[i] += a[i - 1];
p = max_element(a, a + n + 1) - a;
ll l = 1, r = a[p], ans = r;
while(l <= r){
ll mid = (l + r) >> 1;
if(check(mid, a[p] - mid) || check(mid, a[p] - mid + 1))r = mid - 1, ans = mid;
else l = mid + 1;
}
printf("%lld\n",ans);
return 0;
}
2023省选武汉联测5
A. 巴萨
CF1510J
只保留蓝色格子和两个蓝色段之间的一个红色格子,剩下的红色格子可以自由移动
对于一个蓝色段,他的位置取决于左右可自由移动的格子数量
设最靠左时为 有 个可移动格子,那么最靠右为
一定染色的为
枚举 , 每一段向前拓展,然后可以加上长度不超过 的,进行构造
证明 枚举到 即可
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int maxn = 5e6 + 55;
int n; char s[maxn];
vector<int>L;
bool ans[maxn];
bool check(int k){
for(int l = 1, r = 1; l <= n; l = r + 1, r = l)if(ans[l] == false){
while(ans[r + 1] == false) ++r;
int len = r - l + 1;
if(l != 1)len -= r == n ? k : 1;
if(k == 0){if(len)return false;}
if(k == 1){if(len & 1)return false;}
if(k >= 2){if(len == 1)return false;}
}
return true;
}
void print(int k){
for(int l = 1, r = 1; l <= n; l = r + 1, r = l)if(ans[l] == false){
while(ans[r + 1] == false) ++r;
int len = r - l + 1;
if(l != 1){if(r != n) ++l, --len; else len -= k, l += k;}
if(len == 0)continue;
if(len == 1)assert(0);
if(len & 1){
ans[l] = ans[l + 1] = true;
l += 3; len -= 3;
}
while(len){ans[l] = true; l += 2; len -= 2;}
}
printf("Yes\n");
for(int i = 1; i <= n; ++i)if(ans[i])printf("B"); else printf("R"); printf("\n");
}
int main(){
freopen("barca.in","r",stdin);
freopen("barca.out","w",stdout);
scanf("%d",&n); scanf("%s",s + 1);
for(int l = 1, r = l; l <= n; l = r + 1, r = l)if(s[l] == '1'){
while(s[r + 1] == '1' && r < n)++r;
L.push_back(l);
for(int i = l; i <= r; ++i)ans[i] = true;
}
ans[n + 1] = true;
if(L.empty()){
printf("Yes\n");
for(int i = 1; i <= n; ++i)printf("R"); return 0;
}
for(int k = 0; k <= 3; ++k){
if(check(k)){print(k); return 0;}
for(int &x : L){
--x;
if(ans[x] || x == 0 || ans[x - 1]){printf("No\n"); return 0;}
ans[x] = true;
}
if(ans[n - k])break;
}
printf("No\n");
return 0;
}
B. 拜仁
C. 大巴黎
CF794G
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int maxn = 4e6 + 55, mod = 1e9 + 7;
int qpow(int x, int y){
int ans = 1;
for(; y; y >>= 1, x = 1ll * x * x % mod)if(y & 1)ans = 1ll * ans * x % mod;
return ans;
}
char a[maxn], b[maxn];
int n, ans, p2[maxn], fac[maxn], ifac[maxn], f[maxn];
int C(int n, int m){return 1ll * fac[n] * ifac[m] % mod * ifac[n - m] % mod;}
int main(){
// freopen("bayern.in","r",stdin);
// freopen("bayern.out","w",stdout);
scanf("%s%s%d",a + 1,b + 1, &n);
int la = strlen(a + 1), lb = strlen(b + 1);
fac[0] = ifac[0] = p2[0] = 1;
for(int i = 1; i <= max(max(n + 1, la), lb); ++i)p2[i] = p2[i - 1] * 2 % mod;
for(int i = 1; i <= la + lb; ++i)fac[i] = 1ll * fac[i - 1] * i % mod;
ifac[la + lb] = qpow(fac[la + lb], mod - 2);
for(int i = la + lb - 1; i >= 1; --i)ifac[i] = 1ll * ifac[i + 1] * (i + 1) % mod;
for(int i = n; i >= 1; --i){
f[i] = 1ll * (n / i) * (n / i) % mod;
for(int j = i + i; j <= n; j += i)
f[i] = (f[i] - f[j] + mod) % mod;
}
int c = 0;
for(int i = 1; i <= n; ++i)c = (1ll * f[i] * p2[i] + c) % mod;
int da = 0, db = 0, qa = 0, qb = 0;
for(int i = 1; i <= la; ++i)if(a[i] == 'D')++da; else if(a[i] == 'F')++db; else ++qa;
for(int i = 1; i <= lb; ++i)if(b[i] == 'D')--da; else if(b[i] == 'F')--db; else ++qb;
for(int d = -qb; d <= qa; ++d){
int tr = C(qa + qb, qb + d), ta = da + d, tb = db + qa - qb - d;
if(ta == 0 && tb == 0){ans = (1ll * tr * c + ans) % mod; continue;}
if(1ll * ta * tb < 0){
ta = abs(ta); tb = abs(tb);
ans = (1ll * tr * (p2[n / (max(ta, tb) / __gcd(ta, tb)) + 1] - 2 + mod) + ans) % mod;
}
}
if(la == lb){
bool flag = true; int cnt = 0;
for(int i = 1; i <= la; ++i)if(a[i] != '?' && b[i] != '?' && a[i] != b[i])flag = false;
else if(a[i] == '?' && b[i] == '?')++cnt;
if(flag){
ans = (ans - 1ll * p2[cnt] * c % mod + mod) % mod;
ans = (ans + 1ll * p2[cnt] * (p2[n + 1] - 2 + mod) % mod * (p2[n + 1] - 2 + mod)) % mod;
}
}
printf("%d\n", ans);
return 0;
}
2023省选武汉联测6
A. 线性代数
解释一下系数,就是看有奇数/偶数个主元在这一位为 , 因为最大值是所有的异或起来,所以奇数为 偶数为
code
#include<bits/stdc++.h>
using namespace std;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = (x * 10) + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 55, mod = 1e9 + 7;
int f[maxn][maxn][2], n;
void add(int &x, int y){x += y; if(x >= mod) x -= mod;}
int main(){
freopen("algebra.in","r",stdin);
freopen("algebra.out","w",stdout);
n = read(); f[30][0][1] = 1;
for(int i = 30; i > 0; --i){
int now = (n >> (i - 1)) & 1;
for(int j = 0; j <= 30 - i; ++j)
for(int k = 0; k <= 1; ++k)if(f[i][j][k]){
if(!k || now){
add(f[i - 1][j + 1][k && now == 1], f[i][j][k]);
if(j)add(f[i - 1][j][k && now == 1], 1ll * (1 << max(j - 1, 0)) * f[i][j][k] % mod);
}
add(f[i - 1][j][k && now == 0], 1ll * (1 << max(j - 1, 0)) * f[i][j][k] % mod);
}
}
int ans = 0;
for(int i = 0; i <= 30; ++i)add(ans, f[0][i][0]), add(ans, f[0][i][1]);
printf("%d\n",ans);
return 0;
}
B. 森林
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = (x * 10) + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 1e5 + 55;
struct seg{
struct node{
int mi, cnt, tag;
}t[maxn << 2 | 1];
void clear(int x, int l, int r){
t[x].mi = t[x].tag = 0; t[x].cnt = r - l + 1;
if(l == r)return;
int mid = (l + r) >> 1;
clear(x << 1, l, mid);
clear(x << 1 | 1, mid + 1, r);
}
void push_up(int x){
t[x].cnt = 0; t[x].mi = min(t[x << 1].mi, t[x << 1 | 1].mi);
if(t[x << 1].mi == t[x].mi)t[x].cnt += t[x << 1].cnt;
if(t[x << 1 | 1].mi == t[x].mi)t[x].cnt += t[x << 1 | 1].cnt;
}
void upd(int x, int val){
t[x].mi += val;
t[x].tag += val;
}
void push_down(int x){if(t[x].tag)upd(x << 1, t[x].tag), upd(x << 1 | 1, t[x].tag), t[x].tag = 0;}
void modify(int x, int l, int r, int L, int R, int val){
if(L <= l && r <= R)return upd(x, val);
int mid = (l + r) >> 1; push_down(x);
if(L <= mid)modify(x << 1, l, mid, L, R, val);
if(R > mid)modify(x << 1 | 1, mid + 1, r, L, R, val);
push_up(x);
}
}T;
vector<pii>e, op[maxn];
vector<int>g[maxn];
int n, fa[maxn][19], dfn[maxn], tim, dfnr[maxn], dep[maxn];
void dfs(int x){
dfn[x] = ++tim;
for(int i = 1; i <= 18; ++i)fa[x][i] = fa[fa[x][i - 1]][i - 1];
for(int v : g[x])if(v != fa[x][0]){
fa[v][0] = x; dep[v] = dep[x] + 1;
dfs(v);
}
dfnr[x] = tim;
}
int down(int u, int v){
for(int i = 18; i >= 0; --i)if(dep[fa[v][i]] > dep[u])v = fa[v][i];
return v;
}
int LCA(int u, int v){
if(dep[u] < dep[v])swap(u, v);
for(int i = 18; i >= 0; --i)if(dep[u] - dep[v] >= (1 << i))u = fa[u][i];
if(u == v)return u;
for(int i = 18; i >= 0; --i)if(fa[u][i] != fa[v][i])u = fa[u][i], v = fa[v][i];
return fa[u][0];
}
ll ans;
void solve(int x){
for(pii v : op[x])T.modify(1, 1, n, dfn[v.first], dfnr[v.first], -v.second);
ans += T.t[1].cnt;
for(int v : g[x])if(v != fa[x][0]){
T.modify(1, 1, n, 1, n, 1);
T.modify(1, 1, n, dfn[v], dfnr[v], -2);
solve(v);
T.modify(1, 1, n, 1, n, -1);
T.modify(1, 1, n, dfn[v], dfnr[v], 2);
}
for(pii v : op[x])T.modify(1, 1, n, dfn[v.first], dfnr[v.first], v.second);
}
void sol(){
n = read();
T.clear(1, 1, n); tim = 0; e.clear();
for(int i = 1; i <= n; ++i)g[i].clear(), op[i].clear();
for(int i = 1; i < n; ++i){int u = read(), v = read(); e.push_back(pii(u, v));}
for(int i = 1; i < n; ++i){
int u = read(), v = read();
g[u].push_back(v); g[v].push_back(u);
}
dfs(1);
for(pii now : e){
int u = now.first, v = now.second;
int lca = LCA(u, v);
if(lca == u || lca == v){
if(lca == v)swap(u, v);
int t = down(u, v);
op[1].push_back({v, 1});
op[t].push_back({v, -1});
op[v].push_back({1, 1});
op[v].push_back({t, -1});
}else{op[u].push_back({v, 1}); op[v].push_back({u, 1});}
}
for(int i = 1; i <= n; ++i)T.modify(1, 1, n, dfn[i], dfn[i], dep[i]);
ans = n; solve(1); ans /= 2; printf("%lld\n",ans);
}
int main(){
freopen("forest.in","r",stdin);
freopen("forest.out","w",stdout);
int t = read(); for(int i = 1; i <= t; ++i)sol();
return 0;
}
C. 字符串
事实上预处理 的部分过不了,常数大,而且这题时限不太合理
直接做加上记忆化能过,构造数据好像不太容易卡掉
code
#include<bits/stdc++.h>
using namespace std;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = (x * 10) + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 5e5 + 55, inf = 0x3f3f3f3f;
int n, q, rt[maxn], pos[maxn];
char s[maxn];
struct seg{
int cnt;
struct node{int mi, l, r;}t[maxn * 30];
void push_up(int x){t[x].mi = min(t[t[x].l].mi, t[t[x].r].mi);}
int insert(int x, int l, int r, int pos){
int now = ++cnt; t[now] = t[x];
t[now].mi = min(t[now].mi, l);
if(l == r)return now;
int mid = (l + r) >> 1;
if(pos <= mid)t[now].l = insert(t[x].l, l, mid, pos);
else t[now].r = insert(t[x].r, mid + 1, r, pos);
push_up(now); return now;
}
int query(int x, int l, int r, int L){
if(!x)return inf;
if(L <= l)return t[x].mi;
int mid = (l + r) >> 1;
if(L > mid)return query(t[x].r, mid + 1, r, L);
int res = query(t[x].l, l, mid, L);
if(res != inf)return res;
return query(t[x].r, mid + 1, r, L);
}
int merge(int x, int y, int l, int r){
if(!x || !y)return x | y;
int now = ++cnt, mid = (l + r) >> 1;
t[now].l = merge(t[x].l, t[y].l, l, mid);
t[now].r = merge(t[x].r, t[y].r, mid + 1, r);
push_up(now); return now;
}
}T;
unordered_map<int, int>mp[maxn];
int sol(int now, int len){
if(mp[now].count(len))return mp[now][len];
int res = 0, p = T.query(rt[now], 1, n, 1);
while(p <= n){
++res;
p = T.query(rt[now], 1, n, p + len - 1);
}
return mp[now][len] = res;
}
struct SAM{
struct node{
int fa, ch[26], len;
}d[maxn];
int las = 1, cnt = 1;
void insert(int c){
int fa = las, now = las = ++cnt;
d[now].len = d[fa].len + 1;
for(; fa && !d[fa].ch[c]; fa = d[fa].fa)d[fa].ch[c] = now;
if(!fa)d[now].fa = 1;
else{
int x = d[fa].ch[c];
if(d[x].len == d[fa].len + 1)d[now].fa = x;
else{
int clone = ++cnt;
d[clone] = d[x];
d[clone].len = d[fa].len + 1;
d[x].fa = d[now].fa = clone;
for(; fa && d[fa].ch[c] == x; fa = d[fa].fa)d[fa].ch[c] = clone;
}
}
}
vector<int>g[maxn];
int fa[maxn][20];
void dfs(int x){
for(int i = 1; i <= 19; ++i)fa[x][i] = fa[fa[x][i - 1]][i - 1];
for(int v : g[x])if(v != fa[x][0]){
fa[v][0] = x;
dfs(v);
rt[x] = T.merge(rt[x], rt[v], 1, n);
}
}
void build(){
for(int i = 2; i <= cnt; ++i)g[d[i].fa].push_back(i);
dfs(1);
}
int solve(int l, int r){
int len = r - l + 1, now = pos[r];
for(int i = 19; i >= 0; --i)if(d[fa[now][i]].len >= len)now = fa[now][i];
return sol(now, len);
}
}S;
int main(){
// freopen("string.in","r",stdin);
// freopen("string.out","w",stdout);
n = read(), q = read();
scanf("%s",s + 1);
T.t[0].mi = inf;
for(int i = 1; i <= n; ++i){
S.insert(s[i] - 'a');
rt[S.las] = T.insert(rt[S.las], 1, n, i);
pos[i] = S.las;
}
S.build();
for(int i = 1; i <= q; ++i){
int l = read(), r = read();
if(l == r)printf("-1\n");
else printf("%d\n",S.solve(l, r));
}
return 0;
}
2023省选武汉联测7
A. 动点(point)
引用题解
## 题解 - 山路动点(point)
首先不管修改操作,只考虑询问。不难想到用矩阵处理:
- 沿着向量 $v$ 平移:$x \leftarrow x+v_x$,$y \leftarrow y+v_y$
- 逆时针旋转 $\theta$:$x \leftarrow x\cos \theta -y \sin \theta$,$y \leftarrow y \cos \theta + x \sin \theta$
- 投影到方向 $v$ 上:点乘 $v$ 后数乘 $v$,再数乘一个 $\frac{1}{|v|^2}$
以上都可以表示为向量 $(x,y,1)$ 左乘矩阵,而两类指令都可以表示为上面的过程的组合。因此考虑线段树维护矩阵乘积。
再考虑如何把操作加入。一个基本的思想是,操作时我们不显式地更改指令,而是尝试更改坐标系。对于平移操作,我们完全可以先将点$P$ 沿着逆方向平移,完成指令后再沿着正方向平移回来。写成矩阵形式就是把原来的指令矩阵 $M$ 变成 $DMD^{-1}$,其中 $D$ 为沿着向量 $(u,v)$ 平移对应的矩阵。这个很容易往线段树上打个乘法标记维护。对于翻折操作也是差不多的,我们可以尝试先把点翻过去,执行完指令再翻回来。需要注意的是在点翻到镜像位置之后,原有的旋转操作就需要把逆时针转变成顺时针转了。不过这还是很好办,我们对旋转维护 $M,M'$ 分别表示逆时针、顺时针转对应的矩阵即可。那么翻折操作就是把 $M$ 变为 $RM'R$,把 $M'$ 变为 $RMR$,其中 $R$ 是翻折对应的矩阵。
这题没怎么卡精度,应该不需要 `long double` 就能过。
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
int read(){
int x = 0; bool f = false; char c = getchar();
while(!isdigit(c))f = c == '-', c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return f ? -x : x;
}
const int maxn = 1e5 + 55, mod = 998244353;
const double Pi = acos(-1);
int n, m;
struct matrix{
double a[3][3];
matrix(){memset(a, 0, sizeof(a));}
void clear(){memset(a, 0, sizeof(a));}
void I(){clear(); for(int i = 0; i < 3; ++i)a[i][i] = 1;}
friend matrix operator + (const matrix &x, const matrix &y){
matrix res;
for(int i = 0; i < 3; ++i)
for(int j = 0; j < 3; ++j)
res.a[i][j] = x.a[i][j] + y.a[i][j];
return res;
}
friend matrix operator - (const matrix &x, const matrix &y){
matrix res;
for(int i = 0; i < 3; ++i)
for(int j = 0; j < 3; ++j)
res.a[i][j] = x.a[i][j] - y.a[i][j];
return res;
}
friend matrix operator * (const matrix &x, const matrix &y){
matrix res;
for(int i = 0; i < 3; ++i)
for(int k = 0; k < 3; ++k)
for(int j = 0; j < 3; ++j)
res.a[i][j] += x.a[i][k] * y.a[k][j];
return res;
}
};
matrix trans(double u, double v){
matrix res; res.I();
res.a[2][0] = u; res.a[2][1] = v;
return res;
}
matrix rota(double the){
matrix res;
double c = cos(the), s = sin(the);
res.a[0][0] = res.a[1][1] = c;
res.a[1][0] = -s; res.a[0][1] = s;
res.a[2][2] = 1;
return res;
}
matrix tr(double a, double b, double c, bool op){
double fm = a * a + b * b, fz = a * a - b * b;
matrix res; res.a[2][2] = 1;
if(op){
res.a[0][0] = b * b / fm, res.a[1][0] = -a * b / fm, res.a[2][0] = -a * c / fm,
res.a[1][1] = a * a / fm, res.a[0][1] = -a * b / fm, res.a[2][1] = -b * c / fm;
}else{
res.a[0][0] = -fz / fm, res.a[1][0] = -a * b * 2 / fm, res.a[2][0] = -a * c * 2 / fm,
res.a[1][1] = fz / fm, res.a[0][1] = -a * b * 2 / fm, res.a[2][1] = -b * c * 2 / fm;
}
return res;
}
struct seg{
struct node{
matrix v2, v1, a, b;
bool tag;
}t[maxn << 2 | 1];
void upd(int x, matrix a, matrix b, bool tag){
t[x].a = a * t[x].a;
t[x].b = t[x].b * b;
t[x].v1 = a * t[x].v1 * b;
t[x].v2 = a * t[x].v2 * b;
if(tag)t[x].tag ^= 1, swap(t[x].v1, t[x].v2);
}
void push_down(int x){
upd(x << 1, t[x].a, t[x].b, t[x].tag);
upd(x << 1 | 1, t[x].a, t[x].b, t[x].tag);
t[x].a.I(); t[x].b.I(); t[x].tag = 0;
}
void push_up(int x){
t[x].v1 = t[x << 1].v1 * t[x << 1 | 1].v1;
t[x].v2 = t[x << 1].v2 * t[x << 1 | 1].v2;
}
void build(int x, int l, int r){
t[x].a.I(); t[x].b.I(); t[x].tag = 0;
if(l == r){
int op = read(); double a = read(), b = read(), c = read();
if(op & 1){
matrix tmp = trans(-a, -b), re = trans(a, b);
t[x].v1 = tmp * rota(Pi * c / 1800) * re;
t[x].v2 = tmp * rota(-Pi * c / 1800) * re;
}
else t[x].v1 = t[x].v2 = tr(a, b, c, 1);
return;
}
int mid = (l + r) >> 1;
build(x << 1, l, mid);
build(x << 1 | 1, mid + 1, r);
push_up(x);
}
void modify(int x, int l, int r, int L, int R, matrix a, matrix b, bool tag){
if(L <= l && r <= R)return upd(x, a, b, tag);
push_down(x); int mid = (l + r) >> 1;
if(L <= mid)modify(x << 1, l, mid, L, R, a, b, tag);
if(R > mid)modify(x << 1 | 1, mid + 1, r, L, R, a, b, tag);
push_up(x);
}
matrix query(int x, int l, int r, int L, int R){
if(L <= l && r <= R)return t[x].v1;
push_down(x); int mid = (l + r) >> 1;
if(R <= mid)return query(x << 1, l, mid, L, R);
if(L > mid)return query(x << 1 | 1, mid + 1, r, L, R);
return query(x << 1, l, mid, L, R) * query(x << 1 | 1, mid + 1, r, L, R);
}
}T;
int main(){
freopen("point.in","r",stdin);
freopen("point.out","w",stdout);
n = read(), m = read();
T.build(1, 1, n);
for(int i = 1; i <= m; ++i){
int opt = read();
if(opt == 1){
int l = read(), r = read(), u = read(), v = read();
T.modify(1, 1, n, l, r, trans(-u, -v), trans(u, v), 0);
}else if(opt == 2){
int l = read(), r = read(), u = read(), v = read(), w = read();
matrix tmp = tr(u, v, w, 0);
T.modify(1, 1, n, l, r, tmp, tmp, 1);
}else{
int l = read(), r = read(), x = read(), y = read();
matrix tmp = T.query(1, 1, n, l, r);
double px = tmp.a[0][0] * x + tmp.a[1][0] * y + tmp.a[2][0];
double py = tmp.a[0][1] * x + tmp.a[1][1] * y + tmp.a[2][1];
printf("%.10lf %.10lf\n", px, py);
}
}
return 0;
}
B. 有限域方阵期望对数转置相关度(transpose)
code
## 题解 - 有限域方阵期望对数转置相关度(transpose)
由于某些历史遗留问题,下面的 $q$ 都指的是体面里的 $p$。
首先考虑存在 $B$ 满足 $AB=A^T$ 当且仅当 $\operatorname{Col} A=\operatorname{Col} A^T$。记 $r=\operatorname{rank} A$ 表示 $A$ 的秩。稍加分析可以得到 $A$ 一定能被唯一地表示为 $A=C^TMC$,其中 $C\in \mathbb F_q^{n \times r}$ 的列构成 $\operatorname{Col} A$ 的一组代表基,$M \in \mathbb F_q^{r\times r}$ 是 $r$ 阶满秩方阵。
考虑对于每个秩为 $r$ 的方阵 $A$,$R_{\log}(A)$ 要么为 $0$,即行空间与列空间不同;要么 $R_{\log}(A)=1+n(n-r)$。于是我们只需要计算有多少个秩为 $r$ 的方阵 $A$ 满足上述条件即可。这个玩意用 q-analogue 搞一下就是 $\frac{[n]_q!}{[r]_q![n-r]_q!}f_q(r)$,其中 $f_q(r)$ 为容易递推的 $r$ 阶满秩矩阵数。于是随便用一种方法任意模数卷积就好。
btw,估计这题也是能用 EI 的科技推出个线性做法的,不过那玩意我不会
C. 灭国(destroy)
肯定要在拓扑排序的过程中进行
我们用一个 维护当前度数为 的点集合
另开一个 维护已经确定需要加上一条指向他的边的点的集合
考虑当前度数为 的点,尽量出大的,那么从小到大加入 ,直到边用完或者剩下一个点
如果当前剩下的一个点的权比 中最大点的权大,那么删去当前点
否则尝试把当前点加入集合
如果当前 集合为空(成功加入 ) 那么取出 中最大的点删除即可
指向取出点的点实际上取上一个出队的点即可,我赛时想的比较复杂,用的是最后被删掉的标号大于他的点
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 2e5 + 55;
int n, m, k, deg[maxn];
vector<int>g[maxn];
set<int>s, ss;
vector<pii>res;
void print(){
s.clear();
for(pii v : res)g[v.first].push_back(v.second);
for(int i = 1; i <= n; ++i)deg[i] = 0;
for(int x = 1; x <= n; ++x)
for(int v : g[x])++deg[v];
for(int i = 1; i <= n; ++i)if(deg[i] == 0)s.insert(i);
while(!s.empty()){
int x = *s.begin(); s.erase(x);
printf("%d ",x);
for(int v : g[x]){
--deg[v];
if(deg[v] == 0)s.insert(v);
}
} printf("\n");
printf("%d\n",(int)res.size());
for(pii v : res)printf("%d %d\n",v.first, v.second);
}
void solve1(){
while(s.size() == 1){
int x = *s.begin(); s.erase(x);
for(int v : g[x]){
--deg[v];
if(deg[v] == 0)s.insert(v);
}
}
if(!s.empty()){
int in = *s.begin();
s.erase(in); int las;
while(!s.empty()){
int x = *s.begin(); s.erase(x); if(x > in)las = x;
for(int v : g[x]){--deg[v]; if(deg[v] == 0)s.insert(v);}
}
res.push_back(pii(las, in));
}
print();
}
struct seg{
int t[maxn << 2 | 1];
void push_down(int x){if(t[x]){t[x << 1] = t[x << 1 | 1] = t[x];t[x] = 0;}}
void modify(int x, int l, int r, int pos){
if(r <= pos){t[x] = pos; return;}
push_down(x); int mid = (l + r) >> 1;
modify(x << 1, l, mid, pos);
if(pos > mid)modify(x << 1 | 1, mid + 1, r, pos);
}
int query(int x, int l, int r, int pos){
if(l == r)return t[x];
push_down(x); int mid = (l + r) >> 1;
if(pos <= mid)return query(x << 1, l, mid, pos);
else return query(x << 1 | 1, mid + 1, r, pos);
}
}T;
int main(){
freopen("destroy.in","r",stdin);
freopen("destroy.out","w",stdout);
n = read(), m = read(), k = read();
for(int i = 1; i <= m; ++i){
int u = read(), v = read();
++deg[v]; g[u].push_back(v);
}
for(int i = 1; i <= n; ++i)if(deg[i] == 0)s.insert(i);
if(k == 1){
solve1();
return 0;
}
for(int i = 1; i <= n; ++i)if(deg[i] == 0)s.insert(i);
int rb = 0, cnt = 0;
while(cnt < n){
while(rb < k && (s.size() > 1 || (s.size() == 1 && !ss.empty() && *--ss.end() > *s.begin()))){
++rb;
ss.insert(*s.begin());
s.erase(s.begin());
}
++cnt;
if(!s.empty()){
int x = *s.begin(); s.erase(x); T.modify(1, 1, n, x);
for(int v : g[x]){
--deg[v];
if(deg[v] == 0)s.insert(v);
}
}else{
int x = *--ss.end(); res.push_back(pii(T.query(1, 1, n, x), x)); ss.erase(x); T.modify(1, 1, n, x);
for(int v : g[x]){
--deg[v];
if(deg[v] == 0)s.insert(v);
}
}
}
print();
return 0;
}
2023省选武汉联测8
A. Mix
神必数据结构,不想写
code
B. 梦
code
#include"dream.h"
#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int maxn = 2e5 + 55;
unordered_map<int, int>mp[maxn], id[maxn];
map<int, pii>rem[maxn];
queue<pii>q;
int t1, t2, st[maxn], top, f1[maxn], f2[maxn];
int dream(int ID, int Q, int V, int D, int X, int Y, const std::vector<int>* Edges) {
if(Edges[X].size() != D && Edges[Y].size() != D)return -1;
if(Edges[X].size() != D)return Y;
if(Edges[Y].size() != D)return X;
if(X == Y)return X; mp[X][Y] = 0;
while(!q.empty())q.pop();
for(int i = 0; i < V; ++i)f1[i] = -1;
for(int i = 0; i < V; ++i)mp[i].clear(), rem[i].clear(), id[i].clear();
q.push(pii(X, Y)); t1 = t2 = -1;
while(!q.empty()){
int x = q.front().first, y = q.front().second;
q.pop(); int si = Edges[x].size();
for(int i = 0; i < si; ++i){
int a = Edges[x][i], b = Edges[y][i];
if(mp[a].count(b))continue;
if(a == f1[x])continue;
rem[a][b] = pii(x, y); id[a][b] = i;
if(a == b || Edges[a].size() != Edges[b].size()){
t1 = a; t2 = b;
break;
}else if(mp[x][y] < Q - 1){
f1[a] = x;
mp[a][b] = mp[x][y] + 1;
q.push(pii(a, b));
}
}
if(t1 != -1)break;
}
if(t1 == -1){
while(!q.empty())q.pop();
for(int i = 0; i < V; ++i)f2[i] = -1;
for(int i = 0; i < V; ++i)mp[i].clear(), rem[i].clear(), id[i].clear();
q.push(pii(X, Y));
while(!q.empty()){
int x = q.front().first, y = q.front().second;
q.pop(); int si = Edges[x].size();
for(int i = 0; i < si; ++i){
int a = Edges[x][i], b = Edges[y][i];
if(mp[a].count(b))continue;
if(b == f2[y])continue;
rem[a][b] = pii(x, y); id[a][b] = i;
if(a == b || Edges[a].size() != Edges[b].size()){
t1 = a; t2 = b;
break;
}else if(mp[x][y] < Q - 1){
f2[b] = y;
mp[a][b] = mp[x][y] + 1;
q.push(pii(a, b));
}
}
if(t1 != -1)break;
}
if(t1 == -1)return -1;
}
int deg = -1, x = t1, y = t2;
top = 0;
while(x != X || y != Y){
st[++top] = id[x][y];
pii las = rem[x][y];
x = las.first; y = las.second;
}
for(int i = top; i >= 1; --i)deg = move(st[i]);
if(deg == Edges[t1].size())return t1;
else return t2;
}
C. 不平衡度
咕咕咕
code
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】