[复习] 暑假打板

高考完了,耍了快一个月,开始边耍边学习😂

一年多没碰OI了,本来想刷点题回忆下
然鹅我的记忆力不允许

高精加

#include<bits/stdc++.h>
using namespace std;

const int N=600;
char ch[N];
int a[N],b[N],n,m,c[N],x;

int main(){

    // freopen("1.in","r",stdin);

    cin>>ch;
    n=strlen(ch);
    for(int i=0;i<n;++i)
        a[n-i]=ch[i]-48;
    
    cin>>ch;
    m=strlen(ch);
    for(int i=0;i<m;++i)
        b[m-i]=ch[i]-48;
    
    if(n<m) n=m;

    x=0;
    for(int i=1;i<=n;++i){
        c[i]=(a[i]+b[i]+x)%10;
        x=(a[i]+b[i]+x)/10;
    }
    if(x>0) ++n, c[n]=x;
    for(int i=n;i>0;--i)
        printf("%d",c[i]);
    return 0;
}

高精乘

被坑了,注意判零(见32行)

#include<bits/stdc++.h>
using namespace std;

const int N=3000;
int na,nb,n,a[N],b[N],c[N];
char ch[N];

int main(){

    freopen("1.in","r",stdin);

    cin>>ch;
    na=strlen(ch);
    for(int i=0;i<na;++i)
        a[na-i-1]=ch[i]-48;
    
    cin>>ch;
    nb=strlen(ch);
    for(int i=0;i<nb;++i)
        b[nb-i-1]=ch[i]-48;
    
    for(int i=0;i<na;++i)
        for(int j=0;j<nb;++j)
            c[i+j]+=a[i]*b[j];
    
    for(int i=0;i<na+nb;++i){
        c[i+1]+=c[i]/10;
        c[i]%=10;
    }

    n=na+nb-1;
    while(c[n]==0 && n>0) --n;
    while(n>=0) printf("%d",c[n]),--n;
    
    // debug
    // printf("\n");
    // for(int i=0;i<na+nb;++i) printf("%d ",c[i]);

    return 0;
}

并查集

徒手写的时候没加merge
是不可以的:强制father[x]=y认亲可能会把x从原有的并查集里撕出来
多进行几个这种操作整张图就裂开了

#include<bits/stdc++.h>
using namespace std;
#define in Read()

int in{
    int i=0,f=1;char ch=0;
    while(!isdigit(ch) && ch!='-') ch=getchar();
    if(ch=='-') ch=getchar(),f=-1;
    while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48, ch=getchar();
    return i*f;
}

const int N=1e4+5;
int n,m,father[N];

int getfather(int x){return father[x]==x?father[x]:father[x]=getfather(father[x]);}

void merge(int x,int y){
    x=getfather(x), y=getfather(y);
    if(x==y) return;
    father[x]=y;
    return;
}

int main(){

    // freopen("1.in","r",stdin);

    n=in,m=in;
    for(int i=1;i<=n;++i) father[i]=i; //?
    while(m--){
        int z=in,x=in,y=in;
        if(z==1) merge(x,y);
        else{
            if(getfather(x)==getfather(y)) printf("Y\n");
            else printf("N\n");
        }
    }

    return 0;
}

转念一想不能强制father[x]=y认亲可以让他们的爸爸认亲啊
所以去掉merge函数,让原先merge(x,y)的地方变成father[getfather(x)]=getfather(y)
也是对的

二分答案

二分答案就是这样,对也对的离谱,错也错的离谱
明明思路没一点问题,结果还WA9个点
传送门

#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define int long long

int in{
    int i=0,f=1; char ch=0;
    while(!isdigit(ch)&&ch!='-') ch=getchar();
    if(ch=='-') f=-1, ch=getchar();
    while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48, ch=getchar();
    return i*f;
}

const int N=1e6+10;
int n,m,a[N],ans,l,r,mid;

signed main(){

    // freopen("1.in","r",stdin);

    n=in,m=in; l=1;
    for(int i=1;i<=n;++i) a[i]=in, r=max(r,a[i]);
    while(l<r){
        mid=(l+r+1)>>1;
        int sum=0;
        for(int i=1;i<=n;++i)
            if(a[i]>mid) sum+=a[i]-mid;
        if(sum>=m) l=(ans=mid);
        else r=mid-1;
        // printf("%d %d\n",l,r);
    }

    printf("%lld\n",ans);
    return 0;
    
}

顺带一提,分数规划也用二分法做,要推柿子
分数规划经典题是算性价比, n n n个物品性能 a i a_i ai,价格 b i b_i bi
最大化 ∑ a i ∑ b i \frac{\sum a_i}{\sum b_i} biai
推柿子:

∑ a i ∑ b i > m i d ∑ a i − m i d ∑ b i > 0 \frac{\sum a_i}{\sum b_i}> mid\\ \sum a_i -mid\sum b_i>0 biai>midaimidbi>0

一个 m i d mid mid能使得上式成立则该 m i d mid mid合法

树状数组

复健,一打就会

#include<bits/stdc++.h>
using namespace std;
#define in Read()

int in{
    int i=0,f=1; char ch=0;
    while(!isdigit(ch)&&ch!='-') ch=getchar();
    if(ch=='-') f=-1, ch=getchar();
    while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48, ch=getchar();
    return i*f;
}

const int N=1e6+10;
int n,m,t[N];

int lowbit(int i){return i&-i;}

void Add(int p,int x){
    while(p<=n){
        t[p]+=x;
        p+=lowbit(p);
    }
}

int Query(int p){
    int sum=0;
    while(p>0){
        sum+=t[p];
        p-=lowbit(p);
    }
    return sum;
}

int main(){

    // freopen("1.in","r",stdin);

    n=in,m=in;
    for(int i=1;i<=n;++i) Add(i,in);
    for(int i=1;i<=m;++i){
        int opt=in, a=in, b=in;
        if(opt==1) Add(a,b);
        else printf("%d\n",Query(b)-Query(a-1));
    }

    return 0;
    
}

另外一题
区间加?看到区间第一反应是前缀和,想半天发现肯定不行啊
一看以前的记录,麻了是差分😂想反了

#include<bits/stdc++.h>
using namespace std;
#define in Read()

int in{
    int i=0,f=1; char ch=0;
    while(!isdigit(ch)&&ch!='-') ch=getchar();
    if(ch=='-') f=-1, ch=getchar();
    while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48, ch=getchar();
    return i*f;
}

const int N=1e6+10;
int n,m,t[N],a[N];

int lowbit(int i){return i&-i;}

void Add(int p,int x){
    while(p<=n){
        t[p]+=x;
        p+=lowbit(p);
    }
}

int Query(int p){
    int sum=0;
    while(p>0){
        sum+=t[p];
        p-=lowbit(p);
    }
    return sum;
}

int main(){

    // freopen("1.in","r",stdin);

    n=in,m=in;
    for(int i=1;i<=n;++i) Add(i,(a[i]=in)-a[i-1]);
    for(int i=1;i<=m;++i){
        int opt=in;
        if(opt==1){
            int l=in,r=in,x=in;
            Add(l,x), Add(r+1,-x);
        }else{
            int p=in;
            printf("%d\n",Query(p));
        }
    }

    return 0;
    
}

线段树

完蛋,数组大小要*4都搞忘了
证明如下:
n n n个数据,显然线段树层数为 ⌈ log ⁡ 2 n ⌉ \lceil \log_2n\rceil log2n,故所需空间:
∑ i = 1 ⌈ log ⁡ 2 n ⌉ 2 i = 2 × 2 ⌈ log ⁡ 2 n ⌉ − 1 ≤ 2 × 2 log ⁡ 2 n + 1 − 1 ≤ 4 n \sum_{i=1}^{\lceil \log_2n\rceil}2^i=2\times 2^{\lceil \log_2n\rceil}-1\leq 2\times 2^{ \log_2n +1}-1 \leq 4n i=1log2n2i=2×2log2n12×2log2n+114n

#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define int long long

int in{
    int i=0,f=1; char ch=0;
    while(!isdigit(ch)&&ch!='-') ch=getchar();
    if(ch=='-') f=-1, ch=getchar();
    while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48, ch=getchar();
    return i*f;
}

const int N=1e5+5;
int n,m,tre[N<<2],a[N],laz[N<<2];

void push_up(int p){tre[p]=tre[p<<1]+tre[p<<1|1];}

void push_down(int l,int r,int p){
    if(!laz[p]) return;
    int mid=l+r>>1;
    laz[p<<1]+=laz[p];
    laz[p<<1|1]+=laz[p];
    tre[p<<1]+=laz[p]*(mid-l+1);
    tre[p<<1|1]+=laz[p]*(r-mid);
    laz[p]=0; return;
}

void build(int l,int r,int p){
    if(l==r) tre[p]=a[l];
    else{
        int mid=l+r>>1;
        build(l,mid,p<<1);
        build(mid+1,r,p<<1|1);
        push_up(p);
    } return;
}

void update(int L,int R,int val,int l,int r,int p){
    if(L<=l&&r<=R){
        tre[p]+=val*(r-l+1);
        laz[p]+=val;
    }else{
        push_down(l,r,p);
        int mid=l+r>>1;
        if(mid>=L) update(L,R,val,l,mid,p<<1);
        if(mid<R) update(L,R,val,mid+1,r,p<<1|1);
        push_up(p);
    } return;
}

int query(int L,int R,int l,int r,int p){
    if(L<=l&&r<=R) return tre[p];
    push_down(l,r,p);
    int mid=l+r>>1, res=0;
    if(mid>=L) res+=query(L,R,l,mid,p<<1);
    if(mid<R) res+=query(L,R,mid+1,r,p<<1|1);
    return res;
}

signed main(){

    // freopen("1.in","r",stdin);

    n=in,m=in;
    for(int i=1;i<=n;++i) a[i]=in;
    build(1,n,1);
    for(int i=1;i<=m;++i){
        int opt=in;
        if(opt==1){
            int l=in,r=in,k=in;
            update(l,r,k,1,n,1);
        }else{
            int l=in,r=in;
            printf("%lld\n",query(l,r,1,n,1));
        }
    }

    return 0;
    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值