ICPC2023 西安站
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;
}
N. Python Program
模拟题,不改了
快读读出所有数即可。
本文来自博客园,作者:ricky_lin,转载请注明原文链接:https://www.cnblogs.com/rickylin/p/19154274/ICPC_2023_Xian

浙公网安备 33010602011771号