Programer_Sanust:P10001-----A+B Problem(十五种方法)

Programer_Sanust:P10001-----A+B Problem(十五种方法)

  • 0.开头序言
  • 1.题面描述
  • 2.题目思路
  • 3.巨多的方法与AC代码
    • 1.自带的加法(~~本蒟蒻最喜欢的方法~~ )
    • 2.高精度加法
    • 3.递归
    • 4.Floyd
    • 5.SPFA
    • 6.Link-Cut Tree
    • 7.树状数组
    • 8.Splay
    • 9.Dijkstra+STL的优先队列优化
    • 10.人工运算模拟
    • 11.二分查找
    • 12.最小生成树
    • 13.二进制
    • 14.位运算的两种方法
    • 15.最短代码

0.开头序言

Hello 大家好,我是Sanust
今天我们来讲解一道特别水的一道题 — A+B Problem
相信大家还是 萌新蒟蒻 的时候一定都做过这道题吧

好了,废话不多说,让我们看一下今天的题目:


1.题面描述

题目链接

输入两个整数 a,b,输出它们的和(|a|,|b|<109)
注意:
1.有负数哦!
2.C/C++ 的 main 函数必须是 int 类型,而且最后要 return 0。这不仅对洛谷其他题目有效,而且也是 NOIP/NOI/CSP 比赛的要求!

好吧,同志们,我们就从这一题开始,向着大牛的路进发。
任何一个伟大的思想,都有一个微不足道的开始。


2.题目思路

说实在的,这题没啥思路

我在这里提供几种方法

1. 用C++自带的加法运算符
2. 高精度加法(注意负数)

AC代码与更多方法详见下一章


3.巨多的方法与AC代码

注意,这些题解大部分是搬运洛谷题解上的,不喜勿喷

1.自带的加法(本蒟蒻最喜欢的方法

#include 
using namespace std;
int a,b;
int main()
{
	cin>>a>>b;
	cout<<a+b;
	return 0;
}

2.高精度加法

#include
using namespace std;
char a1[1000],b1[1000];
int a[1000]={0},b[1000]={0},c[1000]={0},la,lb,lc,i,x;
int main()
{
    cin>>a1>>b1;
    la=strlen(a1),lb=strlen(b1);
    for(i=0;i<=la-1;i++) a[la-i]=a1[i]-48;
    for(i=0;i<=lb-1;i++) b[lb-i]=b1[i]-48;
    lc=1,x=0;
    while(lc<=la||lc<=lb) c[lc]=a[lc]+b[lc]+x,x=c[lc]/10,c[lc]%=10,lc++;
    c[lc]=x;
    if(c[lc]==0)lc--;
    for(i=lc;i>=1;i--)cout<<c[i];
    return 0;
}

3.递归

#include
using namespace std;
long long a,b,c;
long long dg(long long a)
{
    if(a<=5) return a;
    return (dg(a/2)+dg(a-a/2));
}
int main()
{
    cin>>a>>b;
    c=dg(a)+dg(b);
    cout<<c;
}

4.Floyd

#include
#include
using namespace std;
long long n=3,a,b,dis[4][4];
int main()
{
    cin>>a>>b;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            dis[i][j]=2147483647;
    dis[1][2]=a,dis[2][3]=b;
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    cout<<dis[1][3];
}

5.SPFA

#include
using namespace std;
int n,m,a,b,op,head[200009],next[200009],dis[200009],len[200009],v[200009],l,r,team[200009],pd[100009],u,v1,e;
int lt(int x,int y,int z)
{
    op++,v[op]=y;
    next[op]=head[x],head[x]=op,len[op]=z;
}
int SPFA(int s,int f)
{
    for(int i=1;i<=200009;i++){dis[i]=999999999;}
    l=0,r=1,team[1]=s,pd[s]=1,dis[s]=0;
    while(l!=r)
    {
        l=(l+1)%90000,u=team[l],pd[u]=0,e=head[u];
        while(e!=0)
        {
            v1=v[e];
            if(dis[v1]>dis[u]+len[e])
            {
                dis[v1]=dis[u]+len[e];
                if(!pd[v1]) r=(r+1)%90000,team[r]=v1,pd[v1]=1;
            }
            e=next[e];
        } 
    }
    return dis[f];
}
int main()
{
    scanf("%d%d",&a,&b);
    lt(1,2,a);
    lt(2,3,b);
    printf("%d",SPFA(1,3));
    return 0;
}

注意,接下来的可能会让你懵圈,请谨慎观看!


6.Link-Cut Tree

#include
using namespace std;
struct node 
{
    int data,rev,sum;
    node *son[2],*pre;
    bool judge();
    bool isroot();
    void pushdown();
    void update();
    void setson(node *child,int lr);
}lct[233];
int top,a,b;
node *getnew(int x)
{
    node *now=lct+ ++top;
    now->data=x;
    now->pre=now->son[1]=now->son[0]=lct;
    now->sum=0;
    now->rev=0;
    return now;
}
bool node::judge(){return pre->son[1]==this;}
bool node::isroot()
{
    if(pre==lct)return true;
    return !(pre->son[1]==this||pre->son[0]==this);
}
void node::pushdown()
{
    if(this==lct||!rev)return;
    swap(son[0],son[1]);
    son[0]->rev^=1;
    son[1]->rev^=1;
    rev=0;
}
void node::update(){sum=son[1]->sum+son[0]->sum+data;}
void node::setson(node *child,int lr)
{
    this->pushdown();
    child->pre=this;
    son[lr]=child;
    this->update();
}
void rotate(node *now)
{
    node *father=now->pre,*grandfa=father->pre;
    if(!father->isroot()) grandfa->pushdown();
    father->pushdown();now->pushdown();
    int lr=now->judge();
    father->setson(now->son[lr^1],lr);
    if(father->isroot()) now->pre=grandfa;
    else grandfa->setson(now,father->judge());
    now->setson(father,lr^1);
    father->update();now->update();
    if(grandfa!=lct) grandfa->update();
}
void splay(node *now)
{
    if(now->isroot())return;
    for(;!now->isroot();rotate(now))
    if(!now->pre->isroot())
    now->judge()==now->pre->judge()?rotate(now->pre):rotate(now);
}
node *access(node *now)
{
    node *last=lct;
    for(;now!=lct;last=now,now=now->pre)
    {
        splay(now);
        now->setson(last,1);
    }
    return last;
}
void changeroot(node *now)
{
    access(now)->rev^=1;
    splay(now);
}
void connect(node *x,node *y)
{
    changeroot(x);
    x->pre=y;
    access(x);
}
void cut(node *x,node *y)
{
    changeroot(x);
    access(y);
    splay(x);
    x->pushdown();
    x->son[1]=y->pre=lct;
    x->update();
}
int query(node *x,node *y)
{
    changeroot(x);
    node *now=access(y);
    return now->sum;
}
int main()
{
    scanf("%d%d",&a,&b);
    node *A=getnew(a);
    node *B=getnew(b);
    connect(A,B);
    cut(A,B);
    connect(A,B);
    printf("%d\n",query(A,B)); 
    return 0;
}

7.树状数组

#include
#include
using namespace std;
int lowbit(int a)
{
    return a&(-a);
}
int n=2,m=1,ans[m+1],a[n+1],c[n+1],s[n+1],o=0;
int main()
{
    memset(c,0,sizeof(c));
    s[0]=0;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        s[i]=s[i-1]+a[i];
        c[i]=s[i]-s[i-lowbit(i)];//树状数组创建前缀和优化
    }
        {
            int x=1,y=2;//求a[1]+a[2]的和
            int s1=0,s2=0,p=x-1;
            while(p>0) s1+=c[p],p-=lowbit(p);//树状数组求和操作,用两个前缀和相减得到区间和
            p=y;
            while(p>0) s2+=c[p],p-=lowbit(p);
            o++,ans[o]=s2-s1;
        }
    }
    for(int i=1;i<=o;i++) cout<<ans[i]<<endl;
    return 0;
}

8.Splay

#include 
#define ll long long
#define N 100000
using namespace std;
int sz[N], rev[N], tag[N], sum[N], ch[N][2], fa[N], val[N];
int n, m, rt, x;
void push_up(int x){
    sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1;
    sum[x] = sum[ch[x][1]] + sum[ch[x][0]] + val[x];
}
void push_down(int x){
    if(rev[x]){
        swap(ch[x][0], ch[x][1]);
        if(ch[x][1]) rev[ch[x][1]] ^= 1;
        if(ch[x][0]) rev[ch[x][0]] ^= 1;
        rev[x] = 0;
    }
    if(tag[x]){
        if(ch[x][1]) tag[ch[x][1]] += tag[x], sum[ch[x][1]] += tag[x];
        if(ch[x][0]) tag[ch[x][0]] += tag[x], sum[ch[x][0]] += tag[x];
        tag[x] = 0;
    }
}
void rotate(int x, int &k){
    int y = fa[x], z = fa[fa[x]];
    int kind = ch[y][1] == x;
    if(y == k) k = x;
    else ch[z][ch[z][1]==y] = x;
    fa[x] = z; fa[y] = x; fa[ch[x][!kind]] = y;
    ch[y][kind] = ch[x][!kind]; ch[x][!kind] = y;
    push_up(y); push_up(x);
}
void splay(int x, int &k){
    while(x != k){
        int y = fa[x], z = fa[fa[x]];
        if(y != k) if(ch[y][1] == x ^ ch[z][1] == y) rotate(x, k);
        else rotate(y, k);
        rotate(x, k);
    }
}
int kth(int x, int k){
    push_down(x);
    int r = sz[ch[x][0]]+1;
    if(k == r) return x;
    if(k < r) return kth(ch[x][0], k);
    else return kth(ch[x][1], k-r);
}
void split(int l, int r){
    int x = kth(rt, l), y = kth(rt, r+2);
    splay(x, rt); splay(y, ch[rt][1]);
}
void rever(int l, int r){
    split(l, r);
    rev[ch[ch[rt][1]][0]] ^= 1;
}
void add(int l, int r, int v){
    split(l, r);
    tag[ch[ch[rt][1]][0]] += v;
    val[ch[ch[rt][1]][0]] += v;
    push_up(ch[ch[rt][1]][0]);
}
int build(int l, int r, int f){
    if(l > r) return 0;
    if(l == r){
        fa[l] = f;
        sz[l] = 1;
        return l;
    }
    int mid = l + r >> 1;
    ch[mid][0] = build(l, mid-1, mid);
    ch[mid][1] = build(mid+1, r, mid);
    fa[mid] = f;
    push_up(mid);
    return mid;
}
int asksum(int l, int r){
    split(l, r);
    return sum[ch[ch[rt][1]][0]];
}
int main(){
    //总共两个数
    n = 2;
    rt = build(1, n+2, 0);//建树
    for(int i = 1; i <= n; i++){
        scanf("%d", &x);
        add(i, i, x);//区间加
    }
    rever(1, n);//区间翻转
    printf("%d\n", asksum(1, n));//区间求和
    return 0;
}

9.Dijkstra+STL的优先队列优化

#include 
using namespace std;
const int N=405;
struct Edge {
    int v,w;
};
vector<Edge> edge[N*N];
int n;
int dis[N*N];
bool vis[N*N];
struct cmp {
    bool operator()(int a,int b) {
        return dis[a]>dis[b];
    }
};
int Dijkstra(int start,int end)
{
    priority_queue<int,vector<int>,cmp> dijQue;
    memset(dis,-1,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dijQue.push(start);
    dis[start]=0;
    while(!dijQue.empty()) {
        int u=dijQue.top();
        dijQue.pop();
        vis[u]=0;
        if(u==end)
            break;
        for(int i=0; i<edge[u].size(); i++) {
            int v=edge[u][i].v;
            if(dis[v]==-1 || dis[v]>dis[u]+edge[u][i].w) {
                dis[v]=dis[u]+edge[u][i].w;
                if(!vis[v]) {
                    vis[v]=true;
                    dijQue.push(v);
                }
            }
        }
    }
    return dis[end];
}
int main()
{
    int a,b;
    scanf("%d%d",&a,&b);
    Edge Qpush;
    
    Qpush.v=1;
    Qpush.w=a;
    edge[0].push_back(Qpush);
    
    Qpush.v=2;
    Qpush.w=b;
    edge[1].push_back(Qpush);
    
    printf("%d",Dijkstra(0,2));
    return 0;
}

10.人工运算模拟

#include  
#include 
using namespace std;
int fu=1,f=1,a,b,c=0;
int main()
{
    cin>>a>>b;
    if(a<0&&b>0)fu=2;
    if(a>0&&b<0)fu=3;
    if(a<0&&b<0)f=-1;
    if(a==0){cout<<b;return 0;}
    if(b==0){cout<<a;return 0;} 
    a=abs(a);
    b=abs(b);
    if(a>b&&fu==3)f=1;
    if(b>a&&fu==3)f=-1;
    if(b>a&&fu==2)f=1;
    if(b<a&&fu==2)f=-1;
    if(fu==1)c=a+b;
    if(fu>1)c=max(a,b)-min(a,b);
    c*=f;
    cout<<c;
    return 0;
}

11.二分查找

#include
using namespace std;
int a,b,c;
 int main(){long long l=-int(1e9)<<1,r=int(1e9)<<1;//左边界和右边界
     scanf("%d%d",&a,&b);
     while(r-l>1){c=(l+r)>>1;//二分的步骤
         if(c-b<a)l=c;
         else if(c-b>a)r=c;
             else return printf("%d\n",c),0;
     }if(l!=r)return printf("%d\n",r),0;
 }

12.最小生成树

#include 
#include 
#define INF 2140000000
using namespace std;
struct tree{int x,y,t;}a[10];
bool cmp(const tree&a,const tree&b){return a.t<b.t;}
int f[11],i,j,k,n,m,x,y,t,ans;
int root(int x){if (f[x]==x) return x;f[x]=root(f[x]);return f[x];}
int main(){
    for (i=1;i<=10;i++) f[i]=i;
    for (i=1;i<=2;i++){
        scanf("%d",&a[i].t);
        a[i].x=i+1;a[i].y=1;k++;
    }
    a[++k].x=1;a[k].y=3,a[k].t=INF;
    sort(a+1,a+1+k,cmp);
    for (i=1;i<=k;i++){
    //    printf("%d %d %d %d\n",k,a[i].x,a[i].y,a[i].t);
        x=root(a[i].x);y=root(a[i].y);
        if (x!=y) f[x]=y,ans+=a[i].t; 
    }
    printf("%d\n",ans);
}

13.二进制

#include
#include
#include
#include
#include
using namespace std;
int main()
{
    int a,b,s=0,s1=0,i=0,na=0,nb=0;
    cin>>a>>b;
    if(a<=0) na=1,a*=-1;
    while(a!=0)
    {
        if(a%2!=0)
        s+=pow(2,a%2*i);
        a/=2;
        i++;
    }
    i=0;
    if(na==1) s*=-1;
    if(b<=0) nb=1,b*=-1;
    while(b!=0)
    {
        if(b%2!=0)
        s1+=pow(2,b%2*i);
        b/=2;
        i++;
    }
    if(nb==1) s1*=-1;
    cout<<s+s1;;
    return 0;
}

14.位运算的两种方法

第一种

#include 
using namespace std;
int plus(int a,int b)//这个是加法运算函数
{
    if(b==0)//如果b(进位)是0(没有进位了),返回a的值
        return a;
    else
    {
        int xor,carry;
        xor=a^b;//xor是a和b不进位加法的值
        carry=(a&b)<<1;//carry是a和b进位的值(只有两个都是1才会产生进位,所以是与运算。左移一位是因为二进制加法和十进制加法竖式一样进位要加在左面一位里)
        return plus(xor,carry);//把不进位加法和进位的值的和就是结果
    }
}
int main()
{
    int a,b;
    cin >> a >> b;
    cout << plus(a,b) << endl;
    return 0;

第二种

#include 
int m, n;
int main()
{
    scanf("%d%d", &m, &n);
    int u = m & n;
    int v = m ^ n;
    while (u) {
        int s = v;
        int t = u << 1;
        u = s & t;
        v = s ^ t;
    }
    printf("%d\n", v);
}

15.最短代码

#include 
int main(int a,int b)
{
    return (scanf("%d%d",&a,&b),printf("%d\n",a+b))&0;
}

好了,我是一脸懵逼的Sanust,我们下期再也不见满嘴反话

!%@#&@>+|:’;~`;’}[.,’;$/-/.’];%!

你可能感兴趣的:(洛谷题解)