【2016常州一中夏令营Day7】

序列(sequence)
【题目描述】
蛤布斯有一个序列,初始为空。它依次将 1-n 插入序列,其中 i插到当前第 ai 个数的右边 (ai=0 表示插到序列最左边)。它希望你帮
它求出最终序列。
【输入数据】
第一行一个整数 n。第二行 n 个正整数 a1~an。
【输出数据】
输出一行 n 个整数表示最终序列,数与数之间用一个空格隔开。
【样例输入】
5
0 1 1 0 3
【样例输出】
4 1 3 5 2
【数据范围】
对于 30%的数据,n<=1000。
对于 70%的数据,n<=100000
对于 100%的数据,n<=1000000,0<=ai<i。

题解

从后往前插入,对于一个数,插入到当前第个空格即可。用线段树维护当前第个空格的位置下标。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int n;
int a[1000005],ans[1000005];
struct hh
{
    int l,r,val;
    bool flag;
};
hh lt[5000005];
void build(int root,int l,int r)
{
    int mid;
    lt[root].l=l;
    lt[root].r=r;
    if(l==r)
    {
        lt[root].val=1;
        return;
    }
    mid=(l+r)>>1;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
    lt[root].val=lt[root<<1].val+lt[root<<1|1].val;
}
int query(int root,int now)
{
    int mid;
    if(lt[root].l==lt[root].r) return lt[root].l;
    if(lt[root<<1].val>=now) return query(root<<1,now);
    else return query(root<<1|1,now-lt[root<<1].val);
}
void del(int root,int pre)
{
    if(lt[root].l<=pre&&lt[root].r>=pre) lt[root].val--;
    if(lt[root].l==lt[root].r)
    {
        lt[root].flag=true;
        return;
    }
    if(lt[root<<1].l<=pre&&lt[root<<1].r>=pre) del(root<<1,pre);
    else if(lt[root<<1|1].l<=pre&&lt[root<<1|1].r>=pre) del(root<<1|1,pre);
}

int main()
{
    int i,j,pre;
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);
    scanf("%d",&n);
    for(i=1;i<=n;i++) scanf("%d",&a[i]);
    build(1,1,n);
    for(i=n;i>=1;i--)
    {
        pre=query(1,a[i]+1);
        ans[pre]=i;
        del(1,pre);
    }
    for(i=1;i<=n;i++) printf("%d ",ans[i]);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

背包(pack)
【题目描述】

蛤布斯有 n 个物品和一个大小为 m 的背包,每个物品有大小和价值,它希望你帮它求出背包里最多能放下多少价值的物品。
【输入数据】
第一行两个整数 n,m。接下来 n 行每行两个整数 xi,wi,表示第 i个物品的大小和价值。
【输出数据】
一行一个整数表示最大价值。
【样例输入】
5 100
95 80
4 18
3 11
99 100
2 10
【样例输出】
101
【数据范围】
对于 20%的数据,xi<=1500。
对于 30%的数据,wi<=1500。
对于 100%的数据,n<=40,0<=m<=10^18,0<=xi,wi<=10^15。

题解

折半搜索+二分查找

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int n,tn,cnt,tot;
long long m,ans=0;
struct hh
{
    long long x,w;
}a[45],q[2000005];
void dfsa(int,long long,long long);
void dfsb(int,long long,long long);
long long search(long long);
bool cmp(hh a,hh b){return a.x==b.x?a.w>b.w:a.x<b.x;}
long long maxx(long long a,long long b){return a>b?a:b;}
int main()
{
    int i,j;
    freopen("pack.in","r",stdin);
    freopen("pack.out","w",stdout);
    scanf("%d%lld",&n,&m);
    tn=n>>1;
    for(i=1;i<=n;i++) scanf("%lld%lld",&a[i].x,&a[i].w);
    dfsa(1,0,0);tot=1;
    sort(q+1,q+cnt+1,cmp);
    for(i=2;i<=cnt;i++)
        if(q[i].x!=q[i-1].x) q[++tot]=q[i];
    for(i=1;i<=tot;i++)
        if(q[i].w<q[i-1].w) q[i].w=q[i-1].w;
    dfsb(tn+1,0,0);
    printf("%lld",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}
void dfsa(int pre,long long xx,long long ww)
{
    if(pre>tn)
    {
        q[++cnt]=(hh){xx,ww};
        return;
    }
    dfsa(pre+1,xx,ww);
    if(xx+a[pre].x<=m) dfsa(pre+1,xx+a[pre].x,ww+a[pre].w);
}

void dfsb(int pre,long long xx,long long ww)
{
    long long temp;
    if(pre>n)
    {
        temp=search(m-xx);
        ans=maxx(ans,ww+temp);
        return;
    }
    dfsb(pre+1,xx,ww);
    if(xx+a[pre].x<=m) dfsb(pre+1,xx+a[pre].x,ww+a[pre].w);
}

long long search(long long xx)
{
    int l,r,mid;
    if(xx<q[1].x) return 0;
    l=1;r=tot;
    while(l<r)
    {
        mid=l+r+1>>1;
        if(q[mid].x<=xx) l=mid;
        else r=mid-1;
    }
    return q[l].w;
}

线段树(segment)
【题目描述】
重新定义一个线段树,根结点仍然表示[1,n],但[l,r]的左右儿子分别表示[l,k]和[k+1,r],这里的 k 可以在[l,r)中任取。
每次访问从根结点开始,而且只有在当前结点是叶子结点时才会直接结束访问,否则一定会向下访问。
蛤布斯将对 m 个区间[ai,bi]进行访问,你需要帮他为每个结点选取合适的 k,输出每次访问的结点个数最小和。
【输入数据】
第一行两个整数 n,m,接下来 m 行每行两个整数 ai,bi。
【输出数据】
一行一个整数表示答案。
【样例输入】
6 6
1 4
2 6
3 4
3 5
2 3
5 6
【样例输出】
40
【数据范围】
对于 20%的数据,n<=50,m<=100。
对于 40%的数据,n<=200。
对于 70%的数据,n<=1000。
对于 100%的数据,n<=5000,m<=100000。

题解

f[i,j]表示结点[i,j]的子树中被访问的最小次数,w[i,j]表示结点[i,j]被访问的次数,即与[i,j]相交的区间数。
f[i,j]=min{f[i,k]+f[k+1,j]}+w[i,j] (i<=k<j)
首先预处理出 w,那么这个 dp 复杂度是 O(n^3),用四边形不等式可以优化到 O(n^2)

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
int l[5005],r[5005],f[5005][5005],w[5005][5005];
int main()
{
    int i,j,k,x,y;
    freopen("segment.in","r",stdin);
    freopen("segment.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;++i)
    {
        scanf("%d%d",&x,&y);
        l[x]++;r[y]++;
    }
    for(i=1;i<=n;++i) r[i]+=r[i-1];
    for(i=n;i>=1;i--) l[i]+=l[i+1];
    memset(f,9999999,sizeof f);
    for(i=1;i<=n;i++) f[i][i]=m-r[i-1]-l[i+1];
    for(i=1;i<=n;i++) w[i][i]=i;
    for(k=1;k<=n-1;k++)
        for(i=1;i<=n-k;i++)
        {
            for(j=w[i][i+k-1];j<=w[i+1][i+k]&&j+1<=i+k;++j)
                if(f[i][j]+f[j+1][i+k]<f[i][i+k])
                {
                    f[i][i+k]=f[i][j]+f[j+1][i+k];
                    w[i][i+k]=j;
                }
            f[i][i+k]+=(m-r[i-1]-l[i+k+1]);
        }
    printf("%d",f[1][n]);
    fclose(stdin);
    fclose(stdout);
    return 0;
}
时间: 2024-08-03 23:10:45

【2016常州一中夏令营Day7】的相关文章

【2016常州一中夏令营Day4】

小 W 走迷宫[问题描述]小 W 被小 M 困在了一个方格矩阵迷宫里,矩阵边界在无穷远处,我们做出如下的假设:a. 每走一步时,只能从当前方格移动一格,走到某个相邻的方格上:b. 走过的格子立即塌陷无法再走第二次:c. 只能向北.东.西三个方向走.小 W 走了没多久就累坏了,他很想知道如果允许在方格矩阵上走 N 步,共有多少种不同的方案.( 开始时小 W 就在方格矩阵上的任意位置, 2 种走法只要有一步不一样,即被认为是不同的方案)[输入格式]一行输入 N.[输出格式]一行输出方案个数.[输入输

【2016常州一中夏令营Day2】

小 W 学数学[问题描述]为了测试小 W 的数学水平,果果给了小 W N 个点,问他这 N 个点能构成的三角形个数.[输入格式]第一行一个整数 N,代表点数.接下来 N 行,每行两个非负整数 X.Y,表示一个点的坐标.[输出格式]一个非负整数,即构成三角形个数.[输入输出样例]tri.in       5           0 01 02 00 11 1 tri.out       9 [数据规模]对于 20%的数据:N=3对于另外 40%的数据:保证任意 3 点不在同一直线上对于 100%的

【2016常州一中夏令营Day3】

小 W 摆石子[问题描述]小 W 得到了一堆石子,要放在 N 条水平线与 M 条竖直线构成的网格的交点上.因为小 M 最喜欢矩形了,小 W 希望知道用 K 个石子最多能找到多少四边平行于坐标轴的长方形,它的四个角上都恰好放着一枚石子.[输入格式]第一行三个整数 N,M,K.[输出格式]一个非负整数,即最多的满足条件的长方形数量.[输入输出样例] rectangle.in3 3 8rectangle.out5 rectangle.in7 14 86rectangle.out1398 [数据规模]对

【2016常州一中夏令营Day5】

小 W 拼图[问题描述]小 W 和小 M 一起玩拼图游戏啦~小 M 给小 M 一张 N 个点的图,有 M 条可选无向边,每条边有一个甜蜜值,小 W 要选K 条边,使得任意两点间最多有一条路径,并且选择的 K 条边甜蜜值之和最大.[输入格式]第一行三个正整数 N,M,K.接下来 M 行,每行三个正整数 A,B,C,表示 A.B 两点间有一条甜蜜值为 C 的无向边.[输出格式]一行输出最大甜蜜值之和.[输入输出样例]carpet.in 5 4 31 2 101 3 92 3 74 5 3 carpe

【2016常州一中夏令营Day1】

Problem 1. suffix给定一个单词,如果该单词以 er. ly 或者 ing 后缀结尾,则删除该后缀(题目保证删除后缀后的单词长度不为 0),否则不进行任何操作.Input输入一行,包含一个单词(单词中间没有空格,每个单词最大长度为 32)Output输出按照题目要求处理后的单词.Examplesuffix.in          suffix.outreferer          referScoring? 对于 40% 的数据,单词最大长度不超过 5. 题解 无可奉告 #inc

常州一中B.1

差不多有一个星期左右没有刷题啦>< 就随便抓了一套水了一遍 T1,T3,T4纯模拟,我就不吐槽啦 T2还有点意思,略带数学思想 这种题目以后不用慌呀,自己拿笔好好算算,总会找到规律的呀╮(╯▽╰)╭ 之后要开始刷题啦 暑假作业三天之内写完了= =好像有点快? 之后就是预习啦,五三刷起来~\(≧▽≦)/~ 当然还有oi呀..... 退役的最后一些日子里 常州一中B.1,布布扣,bubuko.com

2017省夏令营Day7 【快速幂,筛法,矩阵快速幂,线段树】

题解:首先,我们可以得到一个规律:经过2次变换后,a和b的值都分别乘2了,所以只要用快速幂就能过啦,但是,要特判n为0的情况. 代码如下: 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define Mod 1000000007 5 using namespace std; 6 long long a,b,n,ans1,ans2; 7 long long power(long long x)

百练8216-分段函数-2016正式A题

百练 / 2016计算机学科夏令营上机考试 已经结束 题目 排名 状态 统计 提问 A:分段函数 查看 提交 统计 提问 总时间限制:  1000ms 内存限制:  65536kB 描述 编写程序,计算下列分段函数y=f(x)的值. y=-x+2.5; 0 <= x < 5 y=2-1.5(x-3)(x-3); 5 <= x < 10 y=x/2-1.5; 10 <= x < 20 输入 一个浮点数N,0 <= N < 20 输出 输出N对应的分段函数值:f

百练6255-单词反转-2016正式B题

百练 / 2016计算机学科夏令营上机考试 已经结束 题目 排名 状态 统计 提问 B:单词翻转 查看 提交 统计 提问 总时间限制:  1000ms 内存限制:  65536kB 描述 输入一个句子(一行),将句子中的每一个单词翻转后输出. 输入 只有一行,为一个字符串,不超过500个字符.单词之间以空格隔开. 输出 翻转每一个单词后的字符串,单词之间的空格需与原文一致. 样例输入 hello world 样例输出 olleh dlrow 1 #include <iostream> 2 #i