1.激光炸弹
题目链接
题解:这题的解法有点类似前缀和,如果这题是给你一个线段,线段上每个点都有其对应的价值,有一个炸弹能摧毁长度为n的线段,求能摧毁的最大总价值,那么通过前缀和来做很容易解决,而这题就是把一维的前缀和变成了二维的前缀和,炸弹的爆炸范围是一个正方形,我们只需要知道对角上2个点的位置就能确定这个三角形,所已我们用一个二维数组 f[x][y] 来表示0 0 点和x,y点所确定的矩形包含的价值.那么这题也就转化为了一个前缀和问题.现在的问题是如何处理这个二维数组
看如下代码(f[i][j]在处理前储存的是该点的价值)
for(int i = 1; i <= 5001; ++ i)
{
for(int j = 1; j <= 5001; ++ j)
{
f[i][j] = f[i][j]+f[i-1][j]+f[i][j-1]-f[i-1][j-1];
}
}
那么这题也就迎刃而解了
c++代码:
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
const int maxn = 5000 + 50;
typedef long long ll;
int f[maxn][maxn];
int main()
{
int n, r;
while(scanf("%d%d", &n, &r) != EOF)
{
if(r == 0)
{
printf("0\n");
continue;
}
int x, y, v;
memset(f, 0, sizeof(f));
for(int i = 0; i < n; ++ i)
{
scanf("%d%d%d", &x, &y, &v);
f[x+1][y+1] = v;
}
for(int i = 1; i <= 5001; ++ i)
{
for(int j = 1; j <= 5001; ++ j)
{
f[i][j] = f[i][j]+f[i-1][j]+f[i][j-1]-f[i-1][j-1];
}
}
int ans = 0;
for(int i = r; i <= 5001; ++ i)
{
for(int j = r; j <= 5001; ++ j)
{
ans = max(ans, f[i][j]-f[i-r][j]-f[i][j-r]+f[i-r][j-r]);
}
}
printf("%d\n", ans);
}
return 0;
}
java代码:
import java.util.Scanner;
public class Main
{
static final int N=5001;
static int[][] s=new int[N+5][N+5];
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int r=sc.nextInt();
for(int i=0;i<n;i++)
{
int x=sc.nextInt();
int y=sc.nextInt();
int v=sc.nextInt();
s[x+1][y+1]=v;
}
for(int i=1;i<=N;i++)
{
for(int j=1;j<=N;j++)
{
s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+s[i][j];
}
}
int _max=0;
for(int i=r;i<=N;i++)
{
for(int j=r;j<=N;j++)
{
if(s[i][j]-s[i-r][j]-s[i][j-r]+s[i-r][j-r]>_max)
_max=s[i][j]-s[i-r][j]-s[i][j-r]+s[i-r][j-r];
}
}
System.out.println(_max);
sc.close();
}
}
2.IncDec Sequence
题目链接
题解:首先这题一个重点,就是区间[l,r]的修改操作。因为这道题目的修改操作有一个特性,就是只加一或者只减一,而不是+x,也不是−x,所以说我们并不需要用到高级的数据结构,线段树和树状数组,而只是需要用差分即可。
如何才能保证每个数都一样,只需要保证相邻2数之差为0即可.假设我们将所有相邻2个数的差存在b[n]这个数组里面,b[n]=a[n]-a[n-1];那么此时我们就是想办法把b[n]这个数组变成0.我们看看题目中一个区间加一或减一对b[n]的影响假设让[a,b]段的数加一 则b[b]减一 b[a]加一 ,为了让b数组尽快变成0 ,通过贪心的思想我们让b数组正负配对,正数减一 负数加一,如果正数或负数存在多的 就让它和b[1],因为b[1]是否为0并不影响
c++代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<int> d;
d.push_back(0);
int n, x, y;
cin >> n;
cin >> x;
for (int i = 1; i < n; i++) {
cin >> y;
d.push_back(y - x);
x = y;
}
long long pos = 0, neg = 0;
for (auto x : d) {
if (x > 0) pos += x;
else neg -= x;
}
cout << min(pos, neg) + abs(pos - neg) << endl;
cout << abs(pos - neg) + 1;
return 0;
}
java代码:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static final int N=100000+10;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n;
long a[]=new long [N];
n= sc.nextInt();
for(int i=1;i<=n;i++)
a[i]=sc.nextInt();
long q,p;
q=0;
p=0;
for(int i=n;i>=2;i--)
{
long x=a[i]-a[i-1];
if(x>0)
q+=x;
else
p-=x;
}
System.out.println(Math.max(q,p));
System.out.println(Math.abs(q-p)+1);
}
}
3.tallest cow
题目链接
题解:为了使每头牛身高最高,由题意可得 第一头牛和最后一头牛可以拥有题目给出的最高身高,然后其余的牛根据差分关系求得即可,假设a,b能相互看见那么说明a,b中间的牛比ab都要矮,那么cha[a+1]-1 cha[b]+1;
c++代码:
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int N, P, H, M;
int a[10005];
bool appear[10005][10005];
int main()
{
cin >> N >> P >> H >> M;
a[1] = H;
for (int i = 1, A, B; i <= M; i ++ )
{
cin >> A >> B;
if(A > B) swap(A, B);
if(!appear[A][B])
{
appear[A][B] = 1;
a[A + 1] --, a[B] ++;
}
}
for (int i = 1; i <= N; i ++ )
a[i] += a[i - 1], cout << a[i] << endl;
return 0;
}
java代码:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
int[] arr = new int[n + 1];
int p = cin.nextInt();
int h = cin.nextInt();
Arrays.fill(arr, h);
int m = cin.nextInt();
Set<String> set = new HashSet<String>();
int[] op = new int[2];
for (int i = 0; i < m; i++) {
op[0] = cin.nextInt(); // A
op[1] = cin.nextInt(); // B
Arrays.sort(op);
if (!set.contains(op[0] + "" + op[1])) {
set.add(op[0] + "" + op[1]);
for (int c = op[0] + 1; c < op[1]; c++)
arr[c]--;
}
}
for (int i = 1; i <= n; i++)
System.out.println(arr[i]);
}
}