20160819训练记录

T1

给定一个序列 ,在第i时刻位置左边插入一个数i 求最后的序列

【题解】倒着做。。插入的位置是左边有空格的位置 用线段树维护一下单点修改

线段树写的优雅一点

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int p,f[4444444],g[4444444],ans[4444444];
int find(int i,int l,int r,int x){
    f[i]--;
    if(l==r)return i-p+1;
    if(f[i<<1]>=x)return find((i<<1),l,(l+r)/2,x);
    else return find((i<<1|1),(l+r)/2+1,r,x-f[i<<1]);
}
#define FO(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);

int main(){
    FO(sequence);
    int n;scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&g[i]);
    for(p=1;p<n;p<<=1)cerr<<p;
    for(int i=p;i<p+p;i++)f[i]=1;
    for(int i=p-1;i>=1;i--)f[i]=f[i*2]+f[i*2+1];
    cerr<<f[1]<<endl;
    for(int i=n;i>=1;i--)ans[find(1,1,p,g[i]+1)]=i;
    for(int i=1;i<=n;i++)printf("%d ",ans[i]);
}

T2

0/1背包

但是

额 对于这个问题 ,我们可以先找到前20个物品对于每个重量的最大价值

然后求出后20个的 然后二分一下两个体积合并的最优值。。记得long long

#include<map>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n,_p;
typedef long long ll;
ll m,ans,w[44],v[44],max_val[1200666];

struct data{
    ll w,v;
}pii[1233333];
inline bool cmp(const data&a,const data&b){
    return a.w<b.w||(a.w==b.w&&a.v<b.v);
}
inline ll max(ll a,ll b){
    return a>b?a:b;
}
int binary_search(ll x){
    int l=1,r=_p,mid=1,ans=1;
    while(l<=r){
        mid=(l+r)/2;
        if(pii[mid].w<=x){
            ans=mid;
            l=mid+1;
        } else r=mid-1;
    }
    return ans;
}
int main(){
    freopen("pack.in","r",stdin);
    freopen("pack.out","w",stdout);
    scanf("%d %I64d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%I64d %I64d",&w[i],&v[i]);

    int hf=(1<<(n/2)),_hf=0;
    for(int i=0;i<hf;i++){
        ll ww=0,vv=0;
        for(int k=1;k<=n/2;k++)if(i&(1<<(k-1)))ww+=w[k],vv+=v[k];
        if(ww<=m){
            data t=(data){ww,vv};pii[++_hf]=t;
        }
    }
    sort(pii+1,pii+_hf+1,cmp);
    for(int i=1;i<=_hf;i++){
        if(pii[i].w!=pii[i+1].w)pii[++_p]=(data)pii[i];

    }
    for(int i=1;i<=_p;i++)max_val[i]=max(max_val[i-1],pii[i].v);
    //for(int i=1;i<=_p;i++)cout<<pii[i].w<<‘ ‘<<pii[i].v<<endl;
    int fff=(1<<(n/2+(n&1)));
    for(int i=0;i<fff;i++){
        ll ww=0,vv=0;
        for(int k=1;k<=n/2+(n&1);k++)if(i&(1<<(k-1)))ww+=w[k+(n>>1)],vv+=v[k+(n>>1)];
        ll t=m-ww;
        //cout<<ww<<‘ ‘<<vv<<endl;
        if(t<0)continue;
        //printf("found(%d) for %d\n",binary_search(t),t);
        ans=max(ans,max_val[binary_search(t)]+vv);
    }
    cout<<ans;
    return 0;
}

/*
dialog
折半搜索
T(n)=O(2^(n/2)*n)
*极限数据还挺快的。。就不优化了 

*/

T3

n,m<=5000

区间dp+四边形不等式

对于每个节点代表的区间[l,r],求出这个子树中最少访问次数,一个节点被访问一次当且仅当查询区间和他相交

 

然后这个东西是一个四边形不等式的形式

#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#include<string>
#include<string.h>
#define il inline
#define re register
#define lowbit(x) (x&(-x))
using namespace std;
typedef long long ll;
int n,m,a[100010],b[100010],s[5010],g[5010][5010],end[5010],begin[5010],c[5010][5010];
ll f[5010][5010];
il void init(){
    for(int l=2;l<=n;l++){
        for(int i=1,j;i<=n-l+1;i++){
            j=i+l-1;f[i][j]=(1ll<<50);
            for(int k=i;k<j;k++){
                if(f[i][j]>f[i][k]+f[k+1][j]+g[i][j]){
                    c[i][j]=k;f[i][j]=f[i][k]+f[k+1][j]+g[i][j];
                }
            }
        }
    }
    cout<<f[1][n];
}
int main(){
    freopen("segment.in","r",stdin);
    freopen("segment.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&a[i],&b[i]);
        end[b[i]]++;begin[a[i]]++;
    }
    for(int i=1;i<=n;i++) end[i]+=end[i-1];
    for(int i=n;i>=1;i--) begin[i]+=begin[i+1];
    for(int i=1;i<=n;i++)
        for(int j=i;j<=n;j++)
            g[i][j]=m-end[i-1]-begin[j+1];
    for(int i=1;i<=n;i++) f[i][i]=g[i][i];
    if(n<=200){
        init();return 0;
    }
    for(int i=1;i<=n;i++) c[i][i]=i;
    for(int l=2;l<=n;l++){
        for(int i=1,j;i<=n-l+1;i++){
            j=i+l-1;f[i][j]=(1ll<<50);
            for(int k=max(i,c[i][j-1]);k<j&&k<=c[i+1][j];k++){
                if(f[i][j]>f[i][k]+f[k+1][j]+g[i][j]){
                    c[i][j]=k;f[i][j]=f[i][k]+f[k+1][j]+g[i][j];
                }
            }
        }
    }
    cout<<f[1][n];
    return 0;
}
时间: 2024-10-12 18:03:23

20160819训练记录的相关文章

斜率优化系列——训练记录

斜率优化训练记录 前言 斜率优化一般用于优化dp的转移,借着训练斜率优化的相关问题来提升一些DP思维.选择老学长留下的专题场来练手,由于该场题数较多,以及个人不太愿意长时间进行单一专题训练,因此开此文来记录断续的训练结果和心得. 记录 题一 由一道简单入门题玩具装箱开头,题意和思路比较简单就不讲了. 代码 #include<bits/stdc++.h> #define dd(x) cout<<#x<<" = "<<x<<&qu

NOI前训练记录

从今年年初开始就没怎么碰oi,学了三个月文化课,然后就是省选到处跑(浪),进了省队后又去北京打(浪)了波(七)铁(天),回家后又生了一星期病,感觉自己noi凉透了... ctsc因为运气的原因有人放弃D3自己才拿到au,apio什么牌都没拿到,自己这么菜的主要原因可能还是没怎么做题吧,五个月不碰oi,已经连dfs都不会了,还有两个月就noi了,再不训练又要为JS丢脸了,自己拿不到au却占了个省队名额,而阿老师邀请赛冠军的水平却没进省队,感觉自己不珍惜这个省队名额真的是说不过去 本文就记录一下本人

Dailight 训练记录

现场赛记录 19 CCPC 湘潭邀请赛  11/Gold 19 ICPC 西安邀请赛 49/Silver 训练规划: hl: 1.深入增强图论,数据结构的能力,包括但不限于树形dp,点分治,多写dp,学习斜率优化,四边形优化 2.保证银牌及以下图论,数据结构,dp的通过率,最好可以在十分钟内出思路 3.养成提交前检查代码的习惯,不出现傻逼错误. 4.学习简单数论(逆元,组合数),尤其是数论结合图论的应用 gbs: 1.加快上机 ->  写完代码过样例 这一过程的速度. 2.减少debug占用机时

二分暑假专题 训练记录 2017-7-29

POJ3258-River Hopscotch 题意: 给你区间[0,L]给你n个石头,然后去除m个石头  最大化 石头间最小的距离 思路: 首先0和L 这两个石头是不可以动的   然后用 s 数组记录 整个区间的石头 然后排序  此时石头的排序就是有序的了  然后二分套模板 接着check函数才是最关键的好的把 从0到 n+1-m   总共就有 n+2-m 个石头了 而由于第0个石头不可以动 , 所以从第一个开始动 同时判断条件是 s[cur] - s[last] < d 而不是 <= #i

dp暑假专题 训练记录

A 回文串的最小划分 题意:给出长度不超过1000的字符串,把它分割成若干个回文字串,求能分成的最少字串数. #include <iostream> #include <cstdio> #include <string.h> #include <string> using namespace std; const int mod = 1e9 + 7; const int maxn = 1000 + 5; const int INF = 0x3f3f3f3f;

训练记录PART1

11/05 bestcoder #93 C 等价于给出很多环,等概率选择N个点,收益为出现过点的环的环长lcm.不同的环只有 \(\sqrt {26}=6\) 个,用\(f_S\)表示点出现在状态为S的那些环里的选取总数,DP一下即可. bestcoder #93 D 考虑meet in the middle.推一下式子,设左侧选的数和为\(A_{left}t\),两两乘积之和为\(B_{left}\),那么满足\(B_{left}+B_{right}+A_{left}*A_{right}>=0

20160813下午训练记录

*下午听说讲课很简单,被拉去隔壁做只可口胡 不可写的题了 T1 江苏省选的时候有道题面差不多的题目,邵战狂当时跟我口胡过这题 我们还是先不考虑1 那么我们选取一个元素,当加入第二个的时候,两个的奇偶性不同,加入第三个数时,肯定不满足. 那么我们特判一下1的数目,然后乱搞一下 int n,a[1234]; bool np[33333333]; int tot,pr[8001234]; const int N=30000000; void sieve(){ for(int i=2;i<=N;i++)

20160818训练记录

T1 "开心题" 每个点如果不是根节点,子树个数等于度数减一.然后随便算一算 T2 数据范围   首先对于两个长度相等的偶数串.把他两两分组 1 2 3 4 5 6 7 8 考虑一个和8相等的(包括交换内部后)的块 先把他调到头部然后调到尾部.然后删除这一块 然后发现这样的可以对每个串求出字典序最小的等价表达..其实随便计算一下就解决了 #include<cstdio> #include<string.h> #include<iostream> #i

20160817训练记录

  类似生成树的做法去边权降序的前k或n-1条边 T2 发现这个东西可以转化成上一行的前缀积乘上行号 质因数肯定是小于n的职数 每个数的指数是一个组合数的形式 XJB算一下好了 #include<cstdio> #include<time.h> #include<assert.h> #include<iostream> #define mod 1000000009 using namespace std; int n,k;int g[2333][2333],