这场vp很友好 最后一分钟过了第5题
A - Brick
n/w即可
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
int main(){
int n,w;
cin>>n>>w;
cout<<n/w<<endl;
return 0;
}
B - Blocks on Grid
求出最小值和总和 sum-nmminv即可
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1e5+10;
int main(){
int n,m;
cin>>n>>m;
int sum=0,minn=0x3f3f3f3f,x;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
scanf("%d",&x);
minn=min(x,minn);
sum+=x;
}
cout<<sum-minn*m*n;
}
C - Unlucky 7
for循环只需8进制和10进制分别判断就行
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
bool check(int x){
int t=x;
while(t){
if(t%10==7)return 1;
t/=10;
}
string res;
while(x){
if(x%8==7)return 1;
x/=8;
}
return 0;
}
int main(){
int n,res=0;
cin>>n;
for(int i=1;i<=n;i++){
if(check(i))res++;
}
cout<<n-res;
return 0;
}
D - Sum of difference
思路:这类题我们都是直接考虑第i个数他对总和的贡献
因为要取绝对值 那么我们直接排序从大到小 然后从前往后一次求出他对前面i-1个数的贡献 加起来即可
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e5+10;
typedef long long LL;
LL a[N];
bool cmp(LL x,LL y){
return x>y;
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
sort(a+1,a+1+n,cmp);
LL ans=0,sum=0;
for(int i=1;i<=n;i++){
ans+=sum-a[i]*(i-1);
sum+=a[i];
}
cout<<ans;
return 0;
}
E - Throne
思路:要使得最后到达王座 那么有 (kx+s)%n=0
我们转换为同余方程kx+s=0(mod n)
把c往右边移动 kx = -s(mod n)
即为求解该方程中x的最小整数解
化为一般形式 kx + n*y = -s
由拓展欧几里得 d=exgcd(k,n,x,y)
如果 s%d!=0那么无解 否则可得 x= -s/d*x%t+t%t
其中t=n/d
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e5+10;
typedef long long LL;
LL a[N];
LL exgcd(LL a,LL b,LL &x,LL &y){
if(b==0){
y=0;
x=1;
return a;
}
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
LL n,s,k,x,y;
scanf("%d%d%d",&n,&s,&k);
int d=exgcd(k,n,x,y);
if(s%d)puts("-1");
else{
int t=n/d;
cout<<(-x*s/d%t+t)%t<<endl;
}
}
}
F - Rook on Grid
思路:按照atcoder官方题解来 首先从上到下扫一遍求出先横再竖着能到达的点的数量 然后再先竖再横 通过线段树或者树状数组来找出没有被扫到的点的数量 把他们相加即可
但是说实话第二部分还是有点难度
首先我们在做完第一步以后
我们将小于a[1]的点的坐标根据b的大小从小到大排一次序
然后一次进行枚举将上一次的点 l+1 到当前点的位置 r在树状数组中加上
query(r-1)+b[r]-query(m);就为先横再竖着没有扫到的点的数量
之所以+b[r]-query(m)的原因时我们在增加的时候 <=b[1]所以其中的差值我们通过+b[r]-query(m)计算可以得到
循环中限制b[1]是为了用树状数组
这里给大家模拟一边
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=2e5+10;
int a[N],b[N],n,m,k;
int lowbit(int x){
return x&(-x);
}
int tr[N];
void add(int x){
for(;x<=m;x+=lowbit(x)){
tr[x]++;
}
}
int pos[N];
int query(int x){
int res=0;
for(;x; x-=lowbit(x)){
res+=tr[x];
}
return res;
}
bool cmp(int x,int y){
return b[x]<b[y];
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
a[i]=m;
for(int i=1;i<=m;i++)
b[i]=n;
for(int i=1;i<=k;i++){
int x,y;
scanf("%d%d",&x,&y);
a[x]=min(a[x],y-1);
b[y]=min(b[y],x-1);
}
LL ans=0;
for(int i=1;i<=b[1];i++){
ans+=a[i];
}
for(int i=1;i<=a[1];i++)pos[i]=i;//排序枚举顺序b小的优先
sort(pos+1,pos+1+a[1],cmp);
int cnt=0;
for(int i=1;i<=a[1];i++){
int l=pos[i-1],r=pos[i];
for(int j=b[l]+1;j<=b[r]&&j<=b[1];j++)//j<=b[1]是为了让a[j]为0时不增加
add(a[j]);
ans+=query(r-1)+b[r]-query(m);//因为a[j]为0不增加所以用 b[r]-query(m) 求出b[1]后续多出的阶段
}
cout<<ans;
}