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;
}