Codeforces Round #816 (Div. 2)
Codeforces Round #816 (Div. 2)
A,B没做
C. Monoblock
大意
我们可以将一组数组相同的数字进行分块,定义其价值为分的块数,如[1,1,1] 可以分成一块,[1,7,7,7,7,7,7,7,9,9,9,9,9,9,9,9,9]是3块,被分成了 [1], [7,7,7,7,7,7,7], and 9,9,9,9,9,9,9,9,9];
有\(1e5\)次询问,每次询问修改数组的一个数字,求修改后,该数组的所有子段的分块和。
分析
观察得到,
如果前后项互异的话,\(ans=\sum_{1}^{n}i*(n-i+1)\),则前后项相同的话,此项贡献为\(i\),因此只需要维护其前后项是否相同即可。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
typedef long long ll;
ll a[N];
int main() {
int n,m;
cin >> n >> m;
for(int i = 1 ; i <= n ; i++) {
cin >> a[i];
}
ll ans = 0;
for(int i = 1 ; i <= n ; i++) {
ll r = 1;
if(a[i]!=a[i+1] && i != n) {
r = n-i*1ll+1;
}
ans += r*i;
}
for(ll i = 1 ; i <= m ; i++ ) {
ll ii,x;
cin >> ii >> x;
if(a[ii]!=a[ii-1] && ii !=1) {
if(a[ii-1]==x) {
ans -= (ii-1)*(n-ii+2);
ans += (ii-1)*1;
}
}
if(a[ii]==a[ii-1] && ii!=1) {
if(a[ii-1]!=x) {
ans -= (ii-1)*1;
ans += (ii-1)*(n-ii+2);
}
}
if(a[ii]!=a[ii+1] && ii != n) {
if(a[ii+1]==x) {
ans -= (ii)*(n-ii+1);
ans += (ii)*1;
}
}
if(a[ii]==a[ii+1] && ii != n) {
if(a[ii+1]!=x) {
ans -= (ii)*1;
ans += (ii)*(n-ii+1);
}
}
a[ii] = x;
printf("%lld\n",ans);
}
}
D. 2+ doors
给定\(Q\)条线索,\(i,j,x\)表示\(a[i]|a[j]=x\),求原序列最小字典序的可能性。
思路
将\(n\)个数字全置1,读入线索时再\(\&x\),然后得到最大。将所有1置0检测是否成立即可得到最小。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+7;
const ll inf = (1ll<<31)-1;
ll a[N];
vector<pair<ll,ll> >e[N];
int main() {
ll n,q;
cin >> n >> q ;
for(int i = 1 ; i <= n ; i++)
a[i] = inf;
for(int i = 1 ; i <= q ; i++) {
ll l,r,x;
scanf("%lld%lld%lld",&l,&r,&x);
a[l]&=x;
a[r]&=x;
e[l].push_back({r,x});
e[r].push_back({l,x});
}
for(int i = 1 ; i <= n ; i++) {
for(int j = 0 ; j <= 30 ; j++) {
if((1<<j)&a[i]) {
bool flag = 1;
for(auto &t:e[i]) {
ll x = t.first;
ll y = t.second;
if((a[x]|a[i]-(1<<j))!=y || x==i) {
flag = 0;
break;
}
}
if(flag)
a[i]-=(1<<j);
}
}
}
for(int i = 1 ; i <= n ; i++)
printf("%lld ",a[i]);
}

浙公网安备 33010602011771号