第二次积分赛题解

A:破坏王

一个简单的贪心,注意到“一面墙的一部分部分如果被破坏,那么这整面墙将被破坏”,我们需要最少的破坏次数,所以我们选区间的时候肯定是能往右选就往右选,我把所有墙按照R(右端点)排序,然后每次破坏时从目前没被破坏的墙中选择R(右端点)最往左靠的墙开始破坏然后将 [R,R+D-1] 这个区间破坏,然后反复去选择,直到所有墙都被破坏。

#include <bits/stdc++.h>
#define int long long
int n,d;
struct node{
	int l,r;
}a[200005];
//按照R排序
int cmd(node x,node y){
	if(x.r!=y.r){
		return x.r<y.r;
	}
	return x.l<y.l;
}
using namespace std;
signed main(){
	cin>>n>>d;
	for(int i=1;i<=n;i++){
		cin>>a[i].l>>a[i].r;
	}
	sort(a+1,a+1+n,cmd);
	int ans=0;
	for(int i=1;i<=n;i++){
        //l,r为当前要破坏的区间
		int l=a[i].r;
		int r=l+d-1;
		while(a[i].l<=r&&i<=n){//如果墙a[i]的左端点在破坏区间内那么这面墙直接被破坏了
            //i++也就是跳过这面墙
			i++;
		}

		i--;
 
		ans++;
	}
	cout<<ans<<endl;
	return 0;
}

B:收藏家

签到题

#include <bits/stdc++.h>
using namespace std;
signed main(){
    int n;
    cin>>n;
    int ans=0;
    ans+=(n/500)*1000;
    n=n%500;
    ans+=n/5*5;
    cout<<ans<<endl;
    return 0;
}

C:贴地砖

一个打印题

#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main(){
  int n,x,y;
  cin>>n>>x>>y;
    //从左往右,从上到下遍历
  for(int i=0;i<n*x;i++){
    for(int j=0;j<n*y;j++){
        
      if((i/x+j/y)%2){//这个点属于偶数砖内
        cout<<"#";
      }
      else cout<<".";//属于奇数砖内
    }
    cout<<endl;
  }
  return 0;
}

D:kk的矩阵乘法
附上kk学长源码

#include<bits/stdc++.h>
typedef long long ll;
const ll mod = 1e9 + 7;
using namespace std;
int main() {
	int t;
	cin >> t;
	for (int j = 1; j <= t; j++) {
		ll n, a1, a2, b1, b2;
		cin >> n >> a1 >> a2 >> b1 >> b2;
		ll sum = 0;
		ll ans = n * (n - 1) / 2;
		for (int i = 1; i <= n; i++) {
			ll temp1 = (ans * a1 % mod + (i - 1) * n * a2 % mod) % mod;
			ll temp2 = ((i - 1) * n * b1 % mod + ans * b2 % mod) % mod;
			sum = (temp1 * temp2 % mod + sum) % mod;
		}
		cout << sum;
		if (j != t) cout << endl;
	}
	return 0;
}

上图为kk学长手写的推论

E:好好好好好数

原本想把除欧拉筛之外的做法卡掉的,但是想了想还是算了

这题的N范围是1e18,但是注意式子,q的指数是3,所以q最多到1e6,p<q,所以我们用欧拉筛预处理1e6之内的素数,然后循环枚举q的值,然后计算对于当前值,有多少数满足就行。

#include <bits/stdc++.h>
#define int long long
using namespace std;
int n;
int p[2000006];//存储素数
int vis[2000005];
int add[2000005];//前缀和数组
int ss(int n){//欧拉筛
	int cnt=0;
	for(int i=2;i<=n;i++){
		if(!vis[i]) p[++cnt]=i;
		for(int j=1;j<=cnt;j++){
			if(i*p[j]>n) break;
			vis[i*p[j]]=1;
			if(i%p[j]==0) break;
		}
	}
	return cnt;//返回素数个数
}

signed main(){
	cin>>n;
	int len=ss(1000000);
	for(int i=1;i<=len;i++){
		add[p[i]]=1;
	}
	for(int i=1;i<=1000000;i++){
		add[i]=add[i-1]+add[i];
	}
	int ans=0;
	for(int i=2;i<=len;i++){//枚举
		int zhi=p[i]*p[i]*p[i];//当前q^3的值
		if(zhi>n) break;
        //找到式子中的p(不是代码中的p数组)能取到的最大位置
		int kk=n/zhi;
		kk=min(p[i]-1,kk);
        //add是前缀和数组
		ans+=add[kk];
		
		
	}
	cout<<ans<<endl;
	return 0;
}

F:距离

一眼看去,好像是个图论题,确实对每个点跑Dijkstra算法确实能过,但是其实稍加分析,我们就可以知道,数据范围才2000,我们n^2暴力枚举每个点也不会超时,然后对于i,j 两点(j>i),他们之间的最短距离可能是 直接从i 到 j ,也有可能是从 i 到 X 然后花费 1 距离到Y,然后再从Y到 j

,也有可能是从 i 到 Y 然后花费 1 距离到X,然后再从X到 j,取上面三种情况的最小值就好了,代码极其精简。

#include<bits/stdc++.h>
typedef long long ll;
const ll mod = 1e9 + 7;
using namespace std;
int ans[20000];
int n,x,y;
int main() {
	int len;
	cin>>n>>x>>y;
	for(int i=1;i<=n-1;i++){
		for(int j=i+1;j<=n;j++){
             //三种情况中取最小值
			len=min(j-i,min(abs(i-x)+1+abs(y-j),abs(i-y)+1+abs(x-j)));
			ans[len]++;
		}
	}
	for(int i=1;i<=n-1;i++) cout<<ans[i]<<endl;
	return 0;
}

  • 17
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值