Codeforces Round #546
A.Nastya Is Reading a Book
题意:一本书共有
n
n
n章,每章为
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri],现在读到
k
k
k页,问剩下没读得包括当前章的章数。
题解:遍历一遍看第
k
k
k页再第几章,
a
n
s
=
n
−
k
+
1
ans=n-k+1
ans=n−k+1
int l[111],r[111];
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>l[i]>>r[i];
int m;
cin>>m;
for(int i=1;i<=n;i++){
if(m>=l[i]&&m<=r[i]){
cout<<n-i+1<<"\n";
return 0;
}
}
return 0;
}
B.Nastya Is Playing Computer Games
题意:有
n
n
n个井盖,每个井盖上有一个石头,每次可以将一个石头移到旁边一个井盖上,若没有石头则可以打开井盖获得硬币,问获得所有硬币的最小代价。
题解:若只有两个井盖,我们可以将石头移到另一个井盖上,然后打开井盖,再移动到下一个井盖,移动两个石头,打开井盖,共6个代价。那么当井盖数大于2时,我们只需要走到下一个井盖,将石头扔到上一个井盖,然后打开,共3个代价即可。若一开始的位置不再端点上,那么可以走到端点,加上这一部分代价,因为你无论怎么走最后都要有走的这一部分代价。
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int n,k;
cin>>n>>k;
cout<<3*n+min(k-1,n-k)<<"\n";
return 0;
}
C.Nastya Is Transposing Matrices
题意:给你两个矩阵,问能否通过若干次子正方形矩阵转置得到两个相同的矩阵。
题解:每次矩阵转置,两个元素其实是关于对角线对称,那么对于一个对角线上的值,我们可以通过若干次转置使得他的顺序可以调整。只需要判断对角线上的值是否完全一致即可。
int mp1[555][555],mp2[555][555];
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>mp1[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>mp2[i][j];
}
}
vector<int>a[1111],b[1111];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i+j].push_back(mp1[i][j]);
b[i+j].push_back(mp2[i][j]);
}
}
for(int i=2;i<=n+m;i++)sort(a[i].begin(),a[i].end()),sort(b[i].begin(),b[i].end());
for(int i=2;i<=n+m;i++){
if(a[i]!=b[i]){
cout<<"NO\n";
return 0;
}
}
cout<<"YES\n";
return 0;
}
D.Nastya Is Buying Lunch
题意:有n个人在排队,给出n个人的编号,你是队伍中最后一个人,给出k个关系,若u在v前面一个,则u,v可以交换位置,问你最多能前进多少距离。
题解:若你能够前进,则前面一个人必须能够和你交换位置,对这个过程进行模拟,从后往前找第一个可以和你交换的人,然后判断他能否到达你前面一个的位置。最多判断k次。
int pos[300500];
map<pair<int,int>,int>mp;
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>pos[i];
for(int i=1,u,v;i<=k;i++){
cin>>u>>v;
mp[make_pair(u,v)]=1;
}
int last=n;
for(int i=n-1;i>=1;i--){
int j;
if(mp[make_pair(pos[i],pos[last])]){
for(j=i;j<last;j++){
if(mp[make_pair(pos[j],pos[j+1])])swap(pos[j],pos[j+1]);
else break;
}
if(j==last)last--;
}
}
cout<<n-last;
return 0;
}
E.Nastya Hasn’t Written a Legend
题意:你有一个
a
a
a数组和
k
k
k数组。若
a
i
+
1
<
a
i
+
k
i
,
a
i
+
1
=
a
i
+
k
i
a_{i+1}<a_i+k_i,a_{i+1}=a_i+k_i
ai+1<ai+ki,ai+1=ai+ki
有
q
q
q次操作,一种问询问
[
l
,
r
]
[l,r]
[l,r]的
∑
i
=
l
r
a
i
\sum_{i=l}^ra_i
∑i=lrai,一种为,
a
k
=
a
k
+
v
a
l
a_k=a_k+val
ak=ak+val
题解:对于加操作来说,若
y
y
y位置
a
y
>
=
a
y
−
1
+
k
y
−
1
a_y>=a_{y-1}+k_{y-1}
ay>=ay−1+ky−1,那么
a
y
a_y
ay不会改变,因为
a
y
a_y
ay不改变,后面的
a
i
a_i
ai也不会改变。这个
y
y
y的位置是单调的,我们可以二分来找到
y
y
y。
找到
y
y
y后,对于
[
x
,
y
]
[x,y]
[x,y]区间的
a
i
a_i
ai都会改变,
a
x
=
a
x
+
v
a
l
,
a
x
+
1
=
a
x
+
k
x
+
v
a
l
,
a
x
+
2
=
a
x
+
k
x
+
k
x
+
1
+
v
a
l
.
.
.
a_x=a_x+val,a_{x+1}=a_x+k_x+val,a_{x+2}=a_{x}+k_x+k_{x+1}+val...
ax=ax+val,ax+1=ax+kx+val,ax+2=ax+kx+kx+1+val...
那么对
[
l
,
r
]
[l,r]
[l,r]求和,则有
∑
i
=
l
r
a
i
=
(
y
−
x
+
1
)
∗
(
a
[
x
]
+
v
a
l
)
+
(
y
−
x
)
∗
k
x
+
(
y
−
x
−
1
)
∗
k
x
+
1
+
.
.
.
k
y
\sum_{i=l}^ra_i=(y-x+1)*(a[x]+val)+(y-x)*k_x+(y-x-1)*k_{x+1}+...k_y
∑i=lrai=(y−x+1)∗(a[x]+val)+(y−x)∗kx+(y−x−1)∗kx+1+...ky
对于后面的一连串的累加我们可以通过前缀来O(1)计算。用b表示
k
i
k_i
ki的前缀和,用c来表示b的前缀和。
那么后面的东西就等价于
c
[
y
]
−
c
[
x
−
1
]
−
(
y
−
x
+
1
)
∗
b
[
x
]
c[y]-c[x-1]-(y-x+1)*b[x]
c[y]−c[x−1]−(y−x+1)∗b[x]
那么
s
u
m
=
(
y
−
x
+
1
)
∗
(
a
[
x
]
+
v
a
l
−
b
[
x
]
)
+
c
[
y
]
−
c
[
x
−
1
]
sum=(y-x+1)*(a[x]+val-b[x])+c[y]-c[x-1]
sum=(y−x+1)∗(a[x]+val−b[x])+c[y]−c[x−1]
我们会发现
a
[
x
]
+
v
a
l
−
b
[
x
]
a[x]+val-b[x]
a[x]+val−b[x]为一个定值,将这个值最为标记进行区间修改即可。(
a
x
+
1
=
a
x
+
k
x
,
b
x
+
1
=
b
x
+
k
x
a_{x+1}=a_x+k_x,b_{x+1}=b_x+k_x
ax+1=ax+kx,bx+1=bx+kx)
struct node{
ll sum,lazy;
ll l,r;
}tree[maxn<<2];
ll a[maxn],b[maxn],c[maxn];
void build(int id,int l,int r){
tree[id].l=l;tree[id].r=r;tree[id].lazy=-inf;
if(l==r){
tree[id].sum=a[l];
return;
}
int mid=(l+r)>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
tree[id].sum=tree[id<<1].sum+tree[id<<1|1].sum;
}
void change(int id,ll val){
if(val==-inf)return ;
int l=tree[id].l,r=tree[id].r;
tree[id].sum=(ll)(r-l+1ll)*val+c[r]-c[l-1];
tree[id].lazy=val;
return;
}
void pushdown(int id){
if(tree[id].lazy==-inf)return;
change(id<<1,tree[id].lazy);
change(id<<1|1,tree[id].lazy);
tree[id].lazy=-inf;
return;
}
void update(int id,int l,int r,int lx,int ly,ll val){
if(l>=lx&&r<=ly){
change(id,val);
return;
}
int mid=(l+r)>>1;
pushdown(id);
if(mid>=lx)update(id<<1,l,mid,lx,ly,val);
if(mid<ly)update(id<<1|1,mid+1,r,lx,ly,val);
tree[id].sum=tree[id<<1].sum+tree[id<<1|1].sum;
}
ll query(int id,int l,int r,int lx,int ly){
if(l>=lx&&r<=ly){
return tree[id].sum;
}
int mid=(l+r)>>1;
pushdown(id);
ll ans=0;
if(mid>=lx)ans+=query(id<<1,l,mid,lx,ly);
if(mid<ly)ans+=query(id<<1|1,mid+1,r,lx,ly);
return ans;
}
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=2;i<=n;i++)cin>>b[i],b[i]+=b[i-1];
for(int i=2;i<=n;i++)c[i]=b[i]+c[i-1];
build(1,1,n);
ll q;
cin>>q;
string s;
for(ll i=1,x,y;i<=q;i++){
cin>>s>>x>>y;
if(s=="+"){
ll tmp=query(1,1,n,x,x);
ll l=x,r=n;
while(l<r){
ll mid=(l+r+1)>>1;
ll tmp1=query(1,1,n,mid,mid);
if(tmp+y+b[mid]-b[x]>tmp1)l=mid;
else r=mid-1;
}
update(1,1,n,x,l,tmp+y-b[x]);
}
else{
cout<<query(1,1,n,x,y)<<"\n";
}
}
return 0;
}