北林ACM没算到底有几天高强度996猝死集训总结·day1

想起来写博客了,正好今天AK了有时间不需要补题赶紧把笔记给写了晚上还要高强度狒狒14

Day1·前缀、差分、二分


前缀和

设一个数列A1 A2 A3 A4 A5 A6……An

那它的前缀和数列就是

S1=A1

S2=A1+A2

S3=A1+A2+A3

Sn=A1+A2+A3+A4+……+An

一维前缀和说白了就是一个数列的前n项的和

任取一个数n,都能找到对应的前缀和,即a1+a2+a3+a4+……an

那,如果是二维的:

如图,这是一个二维方向的数列,我们现在任取一点2,3

那么按照我们刚刚所知道的,他的前缀和应该是把他和他之前所有的值加起来

那么就应该是,如图所示的区域:

即:S(2,3)=A(1,1)+A(1,2)+A(1,3)+A(2,1)+A(2,2)+A(2,3)

如果要写成代码来算前缀和的话,那么就是两个for套在一起,遍历列再遍历行。

好,我们现在知道了它左侧一个数的前缀和,上方一个数的前缀和

 

红色字体的地方是2,2的前缀和,灰色方块的区域是1,3的前缀和

那么红色字体和灰色方块的区域显然是重合的区域,如果我们要算2,3的前缀和的话,我们就必须减去这个区域避免多算。

那么S(2,3)=S(2,2)+S(1,3)-S(1,2)+A(2,3)

推成公式的话,那么就是S(A,B)=S(A-1,B)+S(A,B-1)-S(A-1,B-1)+A(A,B)

(理解不了就画图,拿出高中学物理那一套来。)

差分

高中有个叫错位相减法的玩意儿,就通过A(n)-A(n-1)来构成一个新的数列。

B(1)=A(2)-A(1)

B(2)=A(3)-A(2)

B(n)=A(n+1)-A(n)

这就是差分的公式

如果和刚才所说的类比的话,那在二维的情况下,一维的时候每个数的前一个数将会是两个,即它左边的数和上边的数

即:

  c[i][j]=a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1]

二分

就是司空见惯的二分。。没什么可说的东西

虽然实际应用起来的时候这三个延申出来的东西一个赛着一个不好惹

当日的题目:

A-Square Numbers

给出两个数a,b(a<=b<=100000),求在a和b之间有多少个完全平方数(包括a和b)

 有多组数据,0 0结尾。

样例:

输入

1 4

1 10

0 0

输出:

2

3

有说打表的,实际上最简单的方法是开A和B的平方

例如1 和10

中间的数是4,9

开平方后是1,3.333333333,中间的数是2,3,恰好就是1和10中间完全平方数开方后所得到的数。

代码如下

#include<bits/stdc++.h>
using namespace std;
int main(){
    int a,b;
    while(scanf("%d%d",&a,&b)&&a+b){
        int n = sqrt(a),m = sqrt(b);
        int ans = m-n+1;
        if (n*n!=a)
            cout<<ans-1<<endl;
        else
            cout<<ans<<endl;
    }
    return 0;
}

B - 最大子矩阵

给你一个m×n的整数矩阵,在上面找一个x×y的子矩阵,使子矩阵中所有元素的和最大。

Input输入数据的第一行为一个正整数T,表示有T组测试数据。每一组测试数据的第一行为四个正整数m,n,x,y(0<m,n<1000 AND 0<x<=m AND 0<y<=n),表示给定的矩形有m行n列。接下来这个矩阵,有m行,每行有n个不大于1000的正整数。Output对于每组数据,输出一个整数,表示子矩阵的最大和。

Sample Input

1
4 5 2 2
3 361 649 676 588
992 762 156 993 169
662 34 638 89 543
525 165 254 809 280

Sample Output

2474

首先读入整个矩阵,再将整个矩阵化为前缀和矩阵,再在这个前缀和矩阵中,遍历找到值最大的一个满足条件的矩阵。

总之还是来看代码:

#include<bits/stdc++.h>
using namespace std;
int num[1001][1001]={0};
int main(){
    int N;
    cin>>N;
    while(N--){
    memset(num,0,sizeof(num));
    int x,y,X,Y;
    scanf("%d%d%d%d",&x,&y,&X,&Y);
    for(int a=1;a<=x;a++)
        for(int b=1;b<=y;b++){
            scanf("%d",&num[a][b]);
            num[a][b]=num[a][b]+(num[a][b-1]+num[a-1][b]-num[a-1][b-1]);//将整个矩阵化为前缀和矩阵
        }
    long long int max=0;
    for(int a=1;a<=x-X;a++)
        for(int b=1;b<=y-Y;b++){
            long long int total=num[a+X-1][b+Y-1]-num[a-1][b+Y-1]-num[a+X-1][b-1]+num[a-1][b-1];//在前缀和矩阵中找到满足条件的那一个矩阵
            if(total>=max)
                max=total;
        }
    printf("%lld\n",max);
    }
    return 0;
}

C - Tallest Cow

给出n头牛的身高,和m对关系(a[i]与b[i]可以相互看见。即他们中间的牛都比他们矮)。已知最高的牛为第p头,身高为h。

求每头牛的身高最大可能是多少。

#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
int main(){
    map<pair<int,int>,bool>cow;
    int d[10001]={0},dh[10001]={0};
    int n,highest_t,highest_h,t;
    cin>>n>>highest_t>>highest_h>>t;
    for(int i=0;i<t;i++){
        int a,b;
        cin>>a>>b;
        if(a>b)
            swap(a,b);
        if(cow[make_pair(a,b)])
            continue;
        cow[make_pair(a,b)]=true;
        d[a+1]--;
        d[b]++;
    }
    for(int i=1;i<=n;i++){
        dh[i]=dh[i-1]+d[i];
        cout<<highest_h+dh[i]<<endl;
    }
    return 0;
}

首先建立一个奶牛身高数列,默认这其中的每一头牛都是最高的身高

然后再建立一个差分数列,既然都默认牛都是最高的那个身高了,那此时每一项的值也为0

我们知道这每两头牛之间的每一头牛都比这两头牛矮,那么这两头牛之间的牛的身高显然就要-1

那么他们在差分数列里面相对其他所有的牛也要-1

之后我们再重复这个过程,把每一对的牛都描述清楚

然后再用最高的身高加上这每一头牛的相对高度

AC了!

D - Hamburgers

#include <bits/stdc++.h>
using namespace std;
struct manu{
    long long int B,S,C;
}ger;
int main(){
    long long int a,b,c,num=0;
    char ham[101];
    int i=0;
    while(true){
        char temp;
        temp=getchar();
        if(temp=='\n')
            break;
        else{
            if(temp=='B')
                ger.B++;
            else if(temp=='S')
                ger.S++;
            else if(temp=='C')
                ger.C++;
        }
    }
    long long int total_price=0,x,y,z,money;
    cin>>a>>b>>c;
    cin>>x>>y>>z;
    cin>>money;
    num=100;
    long long int X=a,Y=b,Z=c;
    long long int T=money;
    if(ger.B!=0){
        total_price+=(ger.B*100-a)*x;
        X-=ger.B*100;
    }
    if(ger.S!=0){
        total_price+=(ger.S*100-b)*y;
        Y-=ger.S*100;
    }
    if(ger.C!=0){
        total_price+=(ger.C*100-c)*z;
        Z-=ger.C*100;
    }
    money-=total_price;
    while(money<0&&num>0){
        num--;
        if(ger.B*100-a>0){
        money+=ger.B*x;
        X+=ger.B;
    }
        if(ger.S*100-b>0){
        Y+=ger.S;
        money+=ger.S*y;
    }
        if(ger.C*100-c>0){
        Z+=ger.C;
        money+=ger.C*z;
    }
    }
    if(money>=ger.B*x+ger.S*y+ger.C*z){
        num+=(money/(ger.B*x+ger.S*y+ger.C*z));
    }
    if(X<0)
    T+=X*x;
    if(Y<0)
    T+=Y*y;
    if(Z<0)
    T+=Z*z;
    if(T>=0)
        printf("%I64d\n",num);
    else
        printf("0\n");
    return 0;
    }

是二分!但是可以用模拟来做。

先不管钱够不够,总之先用现有的原料做100个汉堡,不够的原料钱从钱包里扣掉,好的,现在钱成负数了。

我们再一个汉堡一个汉堡的扣掉,直到钱大于0的时候停下。

好,我们现在知道到底能做几个汉堡了。

除此之外再考虑上特殊状况,如果钱没有用完,还可以做多余的汉堡。那就最后再加上还能做的汉堡数量。

这种做法钻了数据的空子,因为数据规定了每种原料最多不超100,那反之就是只要做100个汉堡,无论怎样原料都能用完。

。。。。事后我会把正确的做法补上的吧,大概。

E - 激光炸弹

一种新型的激光炸弹,可以摧毁一个边长为R的正方形内的所有的目标。现在地图上有n(N<=10000)个目标,用整数Xi,Yi(其值在[0,5000])表示目标在地图上的位置,每个目标都有一个价值。激光炸弹的投放是通过卫星定位的,但其有一个缺点,就是其爆破范围,即那个边长为R的正方形的边必须和x,y轴平行。若目标位于爆破正方形的边上,该目标将不会被摧毁。 

#include<bits/stdc++.h>
using namespace std;
int num[5011][5011]={0};
int main(){
    int r,h;
    cin>>h>>r;
    for(int i=1;i<=h;i++){
        int x,y,v;
        cin>>x>>y>>v;
        x++,y++;
        num[x][y]=v;
    }
    for(int i=1; i<=5001; i++) { 
        for(int j=1; j<=5001; j++) {
            num[i][j]=num[i][j]+num[i-1][j]+num[i][j-1]-num[i-1][j-1];
        }
    }
    int Max=0,temp=0;
    for(int a=r;a<=5001;a++){
        for(int b=r;b<=5001;b++){
            Max=max(Max,temp=num[a][b]-num[a][b-r]-num[a-r][b]+num[a-r][b-r]);
        }
    }
    cout<<Max<<endl;
    return 0;
}

直接把B的模板拿过来用就好,什么问题都不会出。

F - Flyer

G - Monitor

那天剩的债

总之,这是day1.

猜你喜欢

转载自www.cnblogs.com/8frames/p/11234087.html