题意: 给定一个长度为 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
#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;
}
题意: 已知序列长度为 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
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;
}