题意:给你若干个从小到大的区间,让你判断x所在区间离最后一个区间差多少。
签到题
#include<bits/stdc++.h>
using namespace std;
int l[105],r[105];
int main()
{
int n,k,ans;
cin>>n;
for(int i=1;i<=n;i++)
cin>>l[i]>>r[i];
cin>>k;
for(int i=1;i<=n;i++)
if(k>=l[i]&&k<=r[i])
ans=n-i+1;
cout<<ans;
}
B. Nastya Is Playing Computer Games
题意:有一个长为n的的地方,你的位置在k,每个地方都有一块石头,石头底下有一块钱,每次移动一格,拿钱,搬开石头放到旁边的格子里各花费1的时间,求捡到n块钱的最小时间花费。
签到题。
#include<bits/stdc++.h>
using namespace std;
int l[105],r[105];
int main()
{
int n,k,ans;
cin>>n>>k;
if(k==1||k==n)ans=3*n;
else
{
int t1=k,t2=n-k+1;
if(t1<t2)
ans=t1*3+t1-1+t2*3-3;
else
ans=t2*3+t2-1+t1*3-3;
}
cout<<ans;
}
C. Nastya Is Transposing Matrices
题意:你可以选取矩阵A的任意多子矩阵,让其元素按照正对角线交换,问是否能将A变成矩阵B。
思路:不难发现,我们把A矩阵每一斜行和B矩阵的每一斜行的元素排序,得到的数组如果不相同就No,如果全部相同就YES。
#include<bits/stdc++.h>
using namespace std;
int a[505][505],b[505][505],c[505],d[505],n,m;
int ok(int x,int y)
{
int N=min(x,(n-y+1));
for(int i=0;i<N;i++)
{
c[i]=a[x-i][y+i];
d[i]=b[x-i][y+i];
}
sort(c,c+N);
sort(d,d+N);
for(int i=0;i<N;i++)
if(c[i]!=d[i])
return 0;
return 1;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&b[i][j]);
n=max(n,m);
for(int i=1;i<=n;i++)
if(!ok(i,1)||!ok(n,i))
puts("NO"),exit(0);
puts("YES");
}
题意:给出n个人的位置,你在最后一个位置,给出m对可以交换的人 a b(a必须刚好在b前面才能交换),问你最多能移到前面多少。
思路:按照位置从后往前枚举每个愿意和你换位置的人,看他能否移到你这里来即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
set<int>s[maxn];
int vis[maxn],a[maxn];
int main()
{
int n,m,u,v;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
s[u].insert(v);
if(a[n]==v)vis[u]=1;
}
for(int i=n-1;i;i--)
if(vis[a[i]])
{
for(int j=i+1;j<n;j++)
if(s[a[j-1]].find(a[j])!=s[a[j-1]].end())
swap(a[j-1],a[j]);
else
break;
}
for(int i=n-1;i;i--)
if(!vis[a[i]])
{
printf("%d\n",n-i-1);
return 0;
}
printf("%d\n",n-1);
}
E. Nastya Hasn't Written a Legend
题意:给你长度为n和长度为n-1的数组,要求ai+ki<=ai+1,有m次操作,分别为查询a数组的区间和,和让ai的值+x。如果更新后ai+1<ai+x,那么ai+1=ai+x,ai+2以及更后面同理。
思路:我们发现如果ai=ai+x后,可能会发生连锁反应,这就不好处理了,但是我们把原来的式子变形,a1<=a2-k1<=a3-k1-k2<=a4-k1-k2-k3<.....对,我们就用线段维护这个序列的区间和及区间最小值,先预处理 bi 为k1+(k1+k2)+(k1+k2+k3)+...+(...+ki-1),那么每次查询得到的值sum+br-bl-1就是答案,每次更新 i x,我先查询x点的值为res,然后从线段树中找到最大的权值不超过res+x的点 r,然后设置区间[ i ,r]的值为res+x即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10;
ll sum[maxn*4],mn[maxn*4],tag[maxn*4],a[maxn],b[maxn],inf=1e18;
void build(int o,int l,int r)
{
tag[o]=inf;
if(l==r)
{
sum[o]=mn[o]=a[l]-b[l];
return;
}
int m=(l+r)/2,ls=o*2,rs=o*2+1;
build(ls,l,m);
build(rs,m+1,r);
sum[o]=sum[ls]+sum[rs];
mn[o]=min(mn[ls],mn[rs]);
}
void pushdown(int o,int ls,int rs,int l,int m,int r)
{
if(tag[o]!=inf)
{
tag[ls]=tag[rs]=mn[ls]=mn[rs]=tag[o];
sum[ls]=1ll*(m-l+1)*tag[o];
sum[rs]=1ll*(r-m)*tag[o];
tag[o]=inf;
}
}
ll qu(int o,int l,int r,int ql,int qr)
{
if(l>=ql&&r<=qr)
return sum[o];
int m=(l+r)/2,ls=o*2,rs=o*2+1;
pushdown(o,ls,rs,l,m,r);
ll res=0;
if(ql<=m)res+=qu(ls,l,m,ql,qr);
if(qr>m)res+=qu(rs,m+1,r,ql,qr);
return res;
}
void up(int o,int l,int r,int ql,int qr,ll v)
{
if(l>=ql&&r<=qr)
{
tag[o]=mn[o]=v;
sum[o]=1ll*v*(r-l+1);
return;
}
int m=(l+r)/2,ls=o*2,rs=o*2+1;
pushdown(o,ls,rs,l,m,r);
if(ql<=m)up(ls,l,m,ql,qr,v);
if(qr>m)up(rs,m+1,r,ql,qr,v);
sum[o]=sum[ls]+sum[rs];
mn[o]=min(mn[ls],mn[rs]);
}
int qu2(int o,int l,int r,ll x)
{
if(l==r)
return l;
int m=(l+r)/2,ls=o*2,rs=o*2+1;
pushdown(o,ls,rs,l,m,r);
if(mn[rs]<=x)return qu2(rs,m+1,r,x);
return qu2(ls,l,m,x);
}
int main()
{
int n,l,r,q;
char s[2];
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(int i=2;i<=n;i++)
scanf("%lld",&b[i]),b[i]+=b[i-1];
build(1,1,n);
for(int i=2;i<=n;i++)
b[i]+=b[i-1];
scanf("%d",&q);
while(q--)
{
scanf("%s%d%d",s,&l,&r);
if(s[0]=='s')
printf("%lld\n",qu(1,1,n,l,r)+b[r]-b[l-1]);
else
{
ll x=qu(1,1,n,l,l)+r;
int cur=qu2(1,1,n,x);
up(1,1,n,l,cur,x);
}
}
}