(Training 10)AtCoder Beginner Contest 186

这场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
我们转换为同余方程k
x+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;
}

猜你喜欢

转载自blog.csdn.net/weixin_45663216/article/details/112798232