A. An Easy Geometry Problem
tag: 二分Hash
我们令 \(A_i' = A_i - i\times \frac k 2\)
那么我们可以发现:
\(
\begin{aligned}A_{i+r}' - A_{i-r}' &= A_{i+r} - (i+r)\times \frac k 2 - (A_{i-r} - (i-r)\times \frac k 2) \\
& = A_{i+r} - A_{i-r} - kr
\end{aligned}\)
所以我们将原本的 \(A_{i+r} - A_{i-r} = kr + b\) 变成了判断 \(A_{i+r}' = A_{i-r}' + b\)
这就可以使用 二分\(Hash\) 进行判断,带修就套一个线段树即可
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll NN = 2e5 + 8,MOD = 1e9+7;
int n,q,k,b;
ll a[NN];
ll pw[NN],pwp[NN];
struct Seg
{int l,r;ll tag;ll lsum,rsum;
#define l(x) tree[x].l
#define r(x) tree[x].r
#define tag(x) tree[x].tag
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
#define lsum(x) tree[x].lsum
#define rsum(x) tree[x].rsum
#define len(x) tree[x].r-tree[x].l+1
}tree[NN << 2];
void addlz(int x,int num)
{tag(x) += num;lsum(x) += pwp[len(x)] * num;rsum(x) += pwp[len(x)] * num;
}
void pushdown(int x)
{addlz(ls(x),tag(x));addlz(rs(x),tag(x));tag(x) = 0;
}
void pushup(int x)
{lsum(x) = lsum(ls(x)) + lsum(rs(x)) * pw[len(ls(x))];rsum(x) = rsum(ls(x)) * pw[len(rs(x))] + rsum(rs(x));
}
void build(int x,int l,int r)
{l(x) = l; r(x) = r;if(l == r){lsum(x) = a[l]+b;rsum(x) = a[l];return;}int mid = (l + r) / 2;build(ls(x),l,mid);build(rs(x),mid+1,r);pushup(x);
}
void modify(int x,int l,int r,int num)
{if(l <= l(x) && r(x) <= r){addlz(x,num);return;}int mid = (l(x) + r(x)) / 2;pushdown(x);if(l <= mid) modify(ls(x),l,r,num);if(mid + 1 <= r) modify(rs(x),l,r,num);pushup(x);
}
ll queryl(int x,int l,int r)
{if(l <= l(x) && r(x) <= r) return lsum(x);int mid = (l(x) + r(x)) / 2;ll lans = 0,rans = 0,ans = 0;pushdown(x);if(l <= mid) lans = queryl(ls(x),l,r);if(mid + 1 <= r) rans = queryl(rs(x),l,r);ans = lans + rans * pw[max(0,mid - max(l,l(x)) + 1)];return ans;
}ll queryr(int x,int l,int r)
{if(l <= l(x) && r(x) <= r) return rsum(x);int mid = (l(x) + r(x)) / 2;ll lans = 0,rans = 0,ans = 0;pushdown(x);if(l <= mid) lans = queryr(ls(x),l,r);if(mid + 1 <= r) rans = queryr(rs(x),l,r);ans = rans + lans * pw[max(min(r,r(x))-(mid+1)+1,0)];return ans;
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> n >> q >> k >> b;pw[0] = 1;for(int i = 1; i <= n; ++i) pw[i] = pw[i-1] * MOD;for(int i = 1; i <= n; ++i) pwp[i] = pwp[i-1] + pw[i-1];for(int i = 1; i <= n; ++i) cin >> a[i];for(int i = 1; i <= n; ++i) a[i] = 2 * a[i] - k * i;b *= 2;build(1,1,n);while(q--){int op;cin >> op;if(op == 1){int l,r,num;cin >> l >> r >> num;modify(1,l,r,2*num);}else{int pos;cin >> pos;int l = 1, r = min(pos-1, n-pos), ans = 0;
// cout << "("<< l << "," << r << "):" << ans << '\n';while(l <= r){int mid = (l + r) / 2;if(queryl(1,pos-mid,pos-1) == queryr(1,pos+1,pos+mid)) l = mid + 1, ans = mid;else r = mid - 1;
// cout << "("<< l << "," << r << "):" << ans << '\n';}cout << ans << '\n';}}return 0;
}
E. Dominating Point
我们发现,如果暴力枚举的话显然是 \(O(n^3)\) 的,但是因为是 \(01\) 传递状态,我们显然可以使用 \(bitset\) 加速,达到 \(O(\frac {n^3} {32})\)
但是也不知道怎么证明,反正无论如何构造都是远远跑不满的,实测可过
code
#include<bits/stdc++.h>
using namespace std;
const int NN = 5e3 + 8;
bitset<NN> A[NN];
bitset<NN> B[NN];
int n;int main() {ios::sync_with_stdio(false),cin.tie(0); cin >> n;for(int i = 0; i < n; ++i){string s;cin >> s;for(int j = 0; j < n; ++j){A[i][j] = B[j][i] = (s[j] == '1');} }vector<int> ans;for(int v = 0; v < n; ++v){bool flag = 0;for(int w = 0; w < n; ++w){if(v == w) continue;if(A[v][w]) continue;if((A[v] & B[w]).any()) continue;flag = 1;break;}if(!flag) ans.push_back(v);}if(ans.size() < 3) cout << "NOT FOUND\n";else for(int i = 0; i < 3; ++i) cout << ans[i] + 1 << ' ';
}
G. An Easy Math Problem
我们首先只记录 \(p,q\) 互质是产生的 \(\frac p q\) 的值。
其次,我们对于 \(p\leq q\) 这个限制非常难受,于是我们就解散这个性质,最后让求出的答案 \(/2\) 即可
我们最后考虑怎么求答案:
我们记 \(n\) 因式分解后结果为:\(n = p_1^{r_1} \times p_2^{r_2}\times \dots p_k^{r_k}\)
我们对于每个质数和质数的次幂,我们把它们分给 \(p/q\) 的方案数为 \(2\times r_i + 1\)
所以最后的答案为 \(\frac {\prod_{i=1}^k (2\times r_i+1) - 1}{2} + 1\) (\(p=1,q=1\) 以上方案中只会被算上一次,所以 \(/2\) 的时候需要单独拎出来)
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int q;
ll n;
ll cnt[40],len;
void solve()
{len = 0;cin >> n;for(ll i = 2; i*i <= n; ++i){if(n % i == 0){cnt[++len] = 0;while(n % i == 0) n /= i, ++cnt[len];}}if(n != 1) cnt[++len] = 1;ll r = 1;for(int i = 1; i <= len; ++i){r *= (2 * cnt[i]) + 1;// cout << cnt[i] << ' ';}r = (r + 1) / 2;cout << r << '\n';
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> q;while(q--){solve();}return 0;
}
H. Elimination Series Once More
归并排序的时候,找到当前比赛区间中比这个数大的数的个数(需要被交换出去的数的个数)
如果比该数大的数的个数 \(\leq k\),并且有这么多小于它的数可以被换进来,那么就可以打到这么多轮次
code
#include <bits/stdc++.h>
using namespace std;
const int NN = (1 << 20) + 8;
int n,k;
struct Perm
{int num;int id;bool operator < (const Perm &x) const{return num < x.num;}
}a[NN];
int now[NN];
int ans[NN];
void solve(int l,int r,int dep)
{// printf("in:(%d,%d,%d)\n",l,r,dep);if(l == r) return;int mid = (l + r) / 2;solve(l,mid,dep-1); solve(mid+1,r,dep-1);int i = l, j = mid+1;for(; i <= mid; ++i){while(j != r+1 && a[j].num < a[i].num){now[a[j].id] += mid - i + 1;if(now[a[j].id] <= k && (a[j].num >> dep) > 0) ans[a[j].id] = dep;++j;}now[a[i].id] += r-j+1;if(now[a[i].id] <= k && (a[i].num >> dep) > 0) ans[a[i].id] = dep;}for(; j <= r; ++j){if(now[a[j].id] <= k && (a[j].num >> dep) > 0) ans[a[j].id] = dep;}// for(int i = 1; i <= (1 << n); ++i)// {// printf("%d ",now[i]);// }// printf("\n");sort(a+l,a+r+1);
}
int main()
{// ios::sync_with_stdio(false),cin.tie(0);cin >> n >> k;for(int i = 1; i <= (1<<n); ++i) cin >> a[i].num, a[i].id = i;solve(1,(1<<n),n);for(int i = 1; i <= (1<<n); ++i) cout << ans[i] << ' ';return 0;
}