长理2019选拔赛1.0

寻宝
描述

在一维坐标轴上有许多宝藏,总共n种宝藏,每种宝藏有k个。现在共k个人寻宝,k个人初始位置可以位于任意点。但是每人需要按指定顺序捡起宝藏(1->2->3->…->n,先捡第1种,再捡第2种。。。最后捡第n种宝藏,每种宝藏捡起一个)。每个人要捡起n个宝藏。现在你自己规划好k个人的初始位置与寻宝路线(一个宝藏只能被一个人捡起),求k个人所走路程的和最短是多少。

输入

第一行两个整数:n,k接下来n行,每行k个整数x,表示宝藏在一维坐标轴上的位置。

(1<=n<=100)

(1<=k<=8)

(-1000,000,000<=x<=1000,000,000)

输出

输出一个数最短的距离和

输入样例 1

2 3
-1 1 3
-2 2 4
输出样例 1
3
提示

样例解释:

第一个人:从-1到-2

第二个人:从1到2

思路:每次都排序。因此数组是按从小到大的顺序排列,可以按顺序计算。

#include <stdio.h>
#include <queue>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <string.h>
#include <string>
#include <map>
#include <set>
#include <deque>
#include <vector>
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
int n,k;
int a[10],b[10];
ll sum;
int main()
{
      scanf("%d %d",&n,&k);
      for(int i=1;i<=n;i++)
      {
            if(i!=1)
            {
                  for(int j=1;j<=k;j++)
                  {
                        b[j]=a[j];/*保存上一组数组*/
                  }
            }
            for(int j=1;j<=k;j++)
            {
                  scanf("%d",&a[j]);
            }
            sort(a+1,a+1+k);/*排序*/
            if(i!=1)
            {
                  for(int j=1;j<=k;j++)
                  {
                        sum+=abs(a[j]-b[j]);
                  }

            }
      }
      printf("%lld\n",sum);
}

线段树

哭泣的阿木木
简略版题目:由于使用了过多的Q技能–绷带牵引,阿木木的绷带库存越来越少,有一天,阿木木去市场上采购绷带,市场上的绷带一共有n种,每一种绷带的价格为 ai ,由于受到金融危机的影响,绷带的价格出现了一些波动,记性很差的阿木木将绷带价格的波动记录了下来,一共有Q次操作,有时阿木木会记录下新的价格波动,有时阿木木会计算一段区间[L,R]的绷带的价格之和,但是阿木木的计算器一不小心丢了,所以请聪明的你们回答阿木木每次询问的结果。

已知第i种价格波动有三种形式:

将区间[L,R]绷带的价格增加k元
将区间[L,R]绷带的价格减少k元
将第i种绷带的价格变为 b 元 每次询问请输出区间[L,R]内绷带的价格之和

输入

第一行输入N和Q(n∈[1,1000000],Q∈[1,1000000])代表N种绷带和Q次询问

接下来一行N个数ai,表示第i种绷带的价格,(ai∈[1,100000])

接下来Q次操作:

q1 L R k 表示将区间[L,R] 内的绷带价格增加k元 (k∈[1,10000],1<=L<R<=n)

q2 L R k 表示将区间[L,R]内的绷带价格减少k元 (k∈[1,10000],1<=L<R<=n)

q3 pos b表示将第pos种绷带的价格修改为b (pos∈[1,n],b∈[1,10000],1<=pos<=n)

q4 L R表示询问区间[L,R]内绷带的价格之和(1<=L<R<=n)

输出

输出每次询问的答案

输入样例 1

9 9
10 8 5 7 5 2 6 1 10
q3 7 1
q1 4 7 5
q2 4 6 7
q4 1 5
q2 1 3 7
q2 3 6 2
q4 4 9
q1 4 9 9
q4 1 8

输出样例 1

31
19
54

思路:裸的建树。

#include <stdio.h>
#include <queue>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <string.h>
#include <string>
#include <map>
#include <set>
#include <deque>
#include <vector>
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
const int maxn=1e6+20;
int n,Q;
ll sum[maxn<<2],add[maxn<<2];/*一般扩大4倍*/
void pushup(int k)/*更新,此题只需求和*/
{
    sum[k]=sum[k<<1]+sum[k<<1|1];
}
void build(int l,int r,int k)/*建树*/
{
    if(l==r)
    {
        scanf("%lld",&sum[k]);
        return;
    }
    int m=(l+r)>>1;
    build(l,m,k<<1);
    build(m+1,r,k<<1|1);
    pushup(k);//递归返回时用儿子结点更新父节点,可进行更新最值、区间和等操作
}
void pushdown(int ln,int rn,int k)/*往下推*/
{
    if(add[k])
    {
        add[k<<1]+=add[k];
        add[k<<1|1]+=add[k];
        sum[k<<1]+=ln*add[k];
        sum[k<<1|1]+=rn*add[k];
        add[k]=0;
    }
}
void up_or_decrease(int L,int R,int l,int r,int c,int k)
{
    /*增减*/
    if(L<=l&&r<=R)
    {
        add[k]+=c;
        sum[k]+=(ll)c*(r-l+1);
        return;
    }
    int m=(l+r)>>1;
    pushdown(m-l+1,r-m,k);
    if(L<=m)
    {
        up_or_decrease(L,R,l,m,c,k<<1);
    }
    if(R>m)
    {
        up_or_decrease(L,R,m+1,r,c,k<<1|1);
    }
    pushup(k);
}
void modify(int l,int r,int c,int pos,int k)
{
    if(l==r)
    {
        add[k]=c;
        sum[k]=(ll)c*(r-l+1);
        return;
    }
    int m=(l+r)>>1;
    pushdown(m-l+1,r-m,k);
    if(pos<=m)
    {
        modify(l,m,c,pos,k<<1);
    }
    if(pos>m)
    {
        modify(m+1,r,c,pos,k<<1|1);
    }
    pushup(k);
}
ll query(int L,int R,int l,int r,int k)
{
    if(L<=l&&r<=R)
    {
        return sum[k];
    }
    int m=(l+r)>>1;
    pushdown(m-l+1,r-m,k);
    ll ans=0;
    if(L<=m)
    {
        ans+=query(L,R,l,m,k<<1);
    }
    if(m<R)
    {
        ans+=query(L,R,m+1,r,k<<1|1);
    }
    return ans;

}
int main()
{
    scanf("%d %d",&n,&Q);
    build(1,n,1);
    int a,b,c;
    while(Q--)
    {
        char s[20];
        scanf("%s",s);
        if(s[1]=='1')
        {
            scanf("%d %d %d",&a,&b,&c);
            up_or_decrease(a,b,1,n,c,1);
        }
        else if(s[1]=='2')
        {
            scanf("%d %d %d",&a,&b,&c);
            up_or_decrease(a,b,1,n,-c,1);
        }
        else if(s[1]=='3')
        {
            scanf("%d %d",&a,&b);
            modify(1,n,b,a,1);
        }
        else if(s[1]=='4')
        {
            scanf("%d %d",&a,&b);
            printf("%lld\n",query(a,b,1,n,1));
        }

    }
}

完全背包求方案数

QAQorz一回到长沙就直奔汉堡王,已知小食的美味度是1,汉堡的美味度是mm,QAQorz一共能吃n美味度的东西,请问QAQorz吃一次汉堡王有几种不同的搭配方案?

关于方案:如果两个方案吃汉堡和小食的先后顺序不同,则称这两种方案是不同的
具体来说:假设一份小食用一个1表示,一个汉堡用m个00表示。当m=2时,先吃一份小食再吃一个汉堡再吃一份小食,方案表示为1001,两个方案不同当且仅当两个01串是不同的。

输入第一行一个数t,表示t(1≤t≤15)组数据。接下来t行,每行两个数表示n和m,1≤n≤2e5, 1≤m≤10

输出

方案数,输出答案对100000007(1e8+7)取模.

输入样例 1
2
2 2
4 2
输出样例
1
2
5

思路:两个不限量的物品,一个需要1的空间,一个需要m的空间。
给你一个容量为n的背包,问有多少种购物方案。

#include <stdio.h>
#include <queue>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <string.h>
#include <string>
#include <map>
#include <set>
#include <deque>
#include <vector>
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
const int maxn=2e5+5;
const int mod=1e8+7;
int t;
int n,m;
int a[2];
int dp[maxn+1];
int  main()
{
      scanf("%d",&t);
      while(t--)
      {
            scanf("%d %d",&n,&m);
            a[0]=1;
            a[1]=m;
            for(int i=0;i<2;i++)
            {
                  dp[0]=1;
                  for(int j=1;j<=n;j++)
                  {
                       dp[j]=(dp[j-1]+dp[j-m])%mod;

                  }
            }
            printf("%d\n",dp[n]);
      }
}

树状数组求逆序对

他看了一场cf的排名。一共有n个人,编号为从1到n。
第一行是第1小时结束时的rank从第1名到第n名的同学的编号
第二行是第2小时结束时的rank从第1名到第n名的同学的编号
Ljb学长想要知道这两个小时之间有多少对同学的排名的相对顺序交换了

输入

第一行是T(1<=T<=10)表示有TT组数据。

后面每组样例的第一行一个数n(1<=n<=100000)表示有n个人。

接下来的一行有n个数表示第一小时结束时从第1名到第n名的同学的编号。

再接下来的一行有n个数表示第二小时结束时从第1名到第n名的同学的编号。

保证T组数据n的和不超过700000。

输出

每组数据输出一个整数,表示答案。
输入样例 1

2
5
5 4 2 1 3
2 5 4 1 3
4
1 2 3 4
1 2 4 3
输出样例 1

2
1

思路:树状数组求逆序对
参考:https://blog.csdn.net/Tc_To_Top/article/details/79562501

#include <stdio.h>
#include <queue>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <string.h>
#include <string>
#include <map>
#include <set>
#include <deque>
#include <vector>
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
int n;
int a[100005],b[100005],c[100005];
int lowbit(int t)
{
    return t&(-t);
}
void Update(int pos, int val)
{
    for (int i = pos; i <= n; i += lowbit(i))
    {
        c[i] += val;
    }
}
int Query(int pos)
{
    int ans = 0;
    for (int i = pos; i > 0; i -= lowbit(i))
    {
        ans += c[i];
    }
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int x;
        ll ans=0;
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&x);
            a[x]=i;
            c[i]=0;
        }
        for(int j=1; j<=n; j++)
        {
            scanf("%d",&x);
            b[j]=a[x];
        }
        for (int i = 1; i <= n; i++)
        {
            Update(b[i], 1);
            ans += i - Query(b[i]);
        }
        printf("%lld\n",ans);

    }
}

素数筛+线段树/树状数组

寒冰射手艾希新学会了一个技能,艾希通过这个技能成为了一名声名远扬的神箭手,从此再也无人敢侵犯弗雷尔卓德!
这个技能的描述如下(假设英雄联盟内的每个人都有一个编号):
假设艾希有x-1(x>=2)个敌人,每个敌人的编号分别为1~x-1,那么艾希的编号就是x。艾希每次使用这个技能,那么对于某个敌人,如果这个敌人的编号的最小素因子小于等于艾希的编号的最小素因子,那么艾希能对他造成致命一击。
现在假设已知有t场战争,每场战争有x-1个敌人,艾希想知道她每场战争使用这个技能能对多少个敌人造成致命一击,由于这个数目太大,她无法计算所以希望你编写一个程序来帮她计算这个结果。
一个x的最小素因子:能够整除xx的最小素数。比如2和4的最小素因子是2,3的最小素因子是3。我们知道1不是素数,但是为了题目的完整性,在这里我们定义1的最小素因子为1。
Input
一个正整数t(t<=1000000),表示有tt组数据。
每组数据输入一个整数x(2<=x<=1000000),表示艾希的编号为x,且敌人数量为x−1。
Output
对于每组数据输出一个整数ans,表示艾希在这场战争中使用该技能能对ans个敌人造成致命一击。
Sample Input 1
2
2
6
Sample Output 1
1
3

#define MAX 1000000
int t;
int x;
int pri[MAX],c[MAX];
int ans[MAX];
int isprime[MAX];
void prime()
{
    for(int i=0; i<=MAX; i++)
    {
        pri[i]=0;
    }
    pri[1]=1;
    for(int i=2; i<=MAX; i++)
    {
        for(int j=i; j<=MAX; j+=i)
        {
            if(!pri[j])
            {
                pri[j]=i;
            }

        }
    }

}
int lowbit(int t)
{
    return t&(-t);
}
void update(int pos,int val)
{
    for(int i=pos; i<=MAX; i+=lowbit(i))
    {
        c[i]+=val;
    }
}
int Query(int pos)
{
    int ans = 0;
    for (int i = pos; i > 0; i -= lowbit(i))
    {
        ans += c[i];
    }
    return ans;
}
int main()
{
    prime();
    for(int i=1; i<=MAX; i++)
    {
        c[i]=0;
    }
    for(int i=1; i<=MAX; i++)
    {
        update(pri[i],1);
        ans[i]=Query(pri[i]);
    }
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&x);
        printf("%d\n",ans[x]-1);

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值