C. Monoblock
题意: 给定一个长度为
n
n
n的序列。定义
g
(
l
,
r
)
g(l,r)
g(l,r)为
a
[
l
:
r
]
a[l:r]
a[l:r]中最长数块的个数,数块的定义为一个区间内的数完全相同。现有
m
m
m个操作,每次操作给定两个整数
p
,
x
p,x
p,x,表示从此刻起,将
a
[
p
]
a[p]
a[p]修改为
x
x
x(注意修改是永久的,这里看错了调了好久嘤嘤嘤),对于每次操作后,求
∑
l
=
1
n
∑
r
=
l
n
g
(
l
,
r
)
\sum\limits_{l = 1}^n \sum\limits_{r = l}^n g(l, r)
l=1∑nr=l∑ng(l,r)。
题解: 很容易维护出原始的
∑
l
=
1
n
∑
r
=
l
n
g
(
l
,
r
)
=
s
u
m
\sum\limits_{l = 1}^n \sum\limits_{r = l}^n g(l, r) = sum
l=1∑nr=l∑ng(l,r)=sum,对于每次操作,先将原
a
[
p
]
a[p]
a[p]在答案中产生的贡献去除,然后将
a
[
p
]
a[p]
a[p]修改为
x
x
x,在将
x
x
x在序列中产生的贡献加上。
a
[
p
]
a[p]
a[p]在序列中的贡献为:若
a
[
p
]
=
=
a
[
p
−
1
]
a[p]==a[p-1]
a[p]==a[p−1],则没有贡献;若
a
[
p
]
!
=
a
[
p
−
1
]
a[p]!=a[p-1]
a[p]!=a[p−1],则贡献为
(
p
−
1
)
∗
(
n
−
p
+
1
)
(p-1)*(n-p+1)
(p−1)∗(n−p+1)。若
a
[
p
]
=
=
a
[
p
+
1
]
a[p]==a[p+1]
a[p]==a[p+1],则没有贡献;若
a
[
p
]
!
=
a
[
p
+
1
]
a[p]!=a[p+1]
a[p]!=a[p+1],则贡献为
p
∗
(
n
−
p
)
p*(n-p)
p∗(n−p)。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=100100;
int n,m,a[N];
ll cnt[N],s[N];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
cnt[i]=cnt[i-1];
if(a[i]!=a[i-1]) cnt[i]++;
}
for(int i=n;i>=1;i--) s[i]=s[i+1]+cnt[i];
ll sum1=0,sum2=0,sum3=0,sum;
for(int i=1;i<=n;i++) sum1+=s[i];
for(int i=1;i<=n;i++) sum2+=1ll*(n-i+1)*cnt[i];
for(int i=1;i<=n;i++) sum3+=n-i+1;
sum=sum1-sum2+sum3;
int p,x;
for(int i=1;i<=m;i++){
scanf("%d%d",&p,&x);
if(a[p]!=a[p-1]) sum-=1ll*(p-1)*(n-p+1);
if(a[p]!=a[p+1]) sum-=1ll*p*(n-p);
a[p]=x;
if(x!=a[p-1]) sum+=1ll*(p-1)*(n-p+1);
if(x!=a[p+1]) sum+=1ll*p*(n-p);
printf("%lld\n",sum);
}
return 0;
}
D. 2+ doors
题意: 已知序列长度为
n
n
n,现给
m
m
m组描述该序列,每组描述给定三个正整数
i
,
j
,
x
i,j,x
i,j,x,表示
a
[
i
]
∣
a
[
j
]
=
=
x
a[i]|a[j]==x
a[i]∣a[j]==x,求字典序最小的序列。
题解: 一开始一直在想每一位的
1
1
1,但是或操作下
1
1
1有很大的不确定性,所以跑偏了
或操作每位相对独立,故按位考虑。首先将每位都置
1
1
1,若两个数相或结果为
0
0
0,那么将该位置$0。之后再每位从
1
1
1到
n
n
n(保证字典序最小)的考虑该位
1
1
1能否删去,即可得到字典序最小的序列。
ps: 注意运算符的优先级,调了好久嘤嘤嘤。
#include<bits/stdc++.h>
using namespace std;
const int N=100100;
int n,m,ans[N];
bool vis[N];
vector< pair<int,int> >ve[N];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) ans[i]=(1<<30)-1;
for(int i=1,a,b,c;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
if(a==b){
ans[a]=c;
vis[a]=1;
continue;
}
ve[a].push_back(make_pair(b,c));
ve[b].push_back(make_pair(a,c));
for(int j=0;j<30;j++){
if((c&(1<<j))==0){
if(ans[a]&(1<<j)) ans[a]^=(1<<j);
if(ans[b]&(1<<j)) ans[b]^=(1<<j);
}
}
}
for(int k=0;k<30;k++){
for(int i=1;i<=n;i++){
if(vis[i]) continue;
if((ans[i]&(1<<k))==0) continue;
int flag=1;
for(int j=0;j<ve[i].size();j++){
int a=i,b=ve[i][j].first,x=ve[i][j].second;
if((x&(1<<k))&&(ans[b]&(1<<k))==0) flag=0;
}
if(flag) ans[i]^=(1<<k);
}
}
for(int i=1;i<=n;i++) printf("%d ",ans[i]);
return 0;
}