zoukankan      html  css  js  c++  java
  • Test 2018-07-19 二中集训

    铁塔

    $ (tower.pas/c/cpp) $

    原题:$ TYVJ 「Poetize8」Tower $

    $ ightarrow $ 戳我进TYVJ原题

    题目描述

    $ Rainbow $ 和 $ Freda $ 要在 $ Poetic Island $ 市的一座山脚下盖房子定居了……盖房 子需要钢材,幸运的是,这里有排成一行的 $ n $ 座废弃的铁塔,从左到右编号为 $ 1 $ 到 $ n $ ,其中第 $ i $ 座的高度为 $ h[i] $ 。 $ Rainbow $ 和 $ Freda $ 想盖一座上面小下面大的城堡,并且城堡的层数尽可能多。 因此,他们要把这些铁塔分成尽量多组,每组内的铁塔编号必须是连续的,并且 从左到右各组内铁塔的高度之和单调不减。最后,他们会用每组铁塔所提供的钢 材构成一层城堡。 但是 $ Rainbow $ 和 $ Freda $ 简直弱爆了有木有,于是请你帮忙计算一下最多能分 成多少组呢?

    输入格式

    第一行一个整数 $ n $ 。 第二行 $ n $ 个整数,第 $ i $ 个整数表示 $ h[i] $ 。

    输出格式

    输出一个整数,表示($ n - $ 最多能分成的组数)。

    样例输入

     8
     1 9 9 4 1 2 2 9 
    
    

    样例输出

     3 
    
    

    样例解释

    样例可分成 $ 1、9、9、4 1 2 2、9, $ 各组的和分别为 $ 1 9 9 9 9 $ ,单调不减。因 此输出 $ n- $ 最大组数 $ =3 $。

    数据范围与约定

    对于30%的数据,$ 0< n le 100 $ 。
    对于70%的数据,$ 0< n le 5000 $ 。
    对于100%的数据,$ 0< n le 200000,0< h[i] le 2147483647,h $均为随机生成。

    题解

    • 这道题最先想到的就是贪心,但是纯贪心明显是不对的,
    • 如 $ 2 2 1 3 3 $ 贪心结果为 $ 2 2 (133)$ 但实际是$ 2 (21) 3 3 $ 。
    • 所以这样是不对的。
    • 那要怎么做呢.....考虑用 $ dp $ .........
    • 阶段应该是明显的就是第几个数,我们还是要用到贪心的思想,
    • 就是保证在最后面的合起来的数尽可能的小
    • $ f[i] $ 表示到第i这个数的最多的组数。
    • $ b[i] $ 表示从1到i的所有数的和(很明显如果合并从 $ k $ 到 $ i $ 那么合并后的数就是 $ b[i]-b[k] $ );
    • $ s[i] $ 表示到第i这个阶段的最后一个数的大小。
    • 所以转移方程就是:$ f[i]=max(f[k]+1);quad (b[i]-b[k] ge s[k]) quad s[i]=b[i]-b[k]; $
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    int n,h,f[200010];
    ll b[200010],s[200010];
    int main(){
    	scanf("%d",&n);
    	for(int h,i=1;i<=n;++i){ scanf("%d",&h); b[i]=b[i-1]+h; }
    	for(int i=1;i<=n;++i)
    		for(int k=i-1;k>=0;--k)
    			if(b[i]-b[k]>=s[k]){
    				f[i]=f[k]+1;
    				s[i]=b[i]-b[k];
    				break;
    			}
    	printf("%d",n-f[n]);
    	return 0;
    }
    

    工作计划

    $ (work.pas/c/cpp) $

    原题:luogu P2948 [USACO09OPEN]滑雪课Ski Lessons

    $ ightarrow $ 戳我进洛谷原题

    题目描述

    $ Mark $ 在无意中了解到了 Elf 的身世。在和 $ James $ 商量过之后,好心的他们 打算送 $ Elf $ 返回故乡。然而,去往 $ Gliese $ 的飞船票价高的惊人,他们暂时还付 不起这笔费用。经过一番考虑,$ Mark $ 打算去额外做一些工作来获得收入。 经过一番调查,$ Mark $ 发现有 $ N $ 个工作可以做。做第 $ i $ 件工作所需要的时 间为 $ Di $ ,同时也需要一个能力值 $ Ci $ 才可以去做,每件工作都可以在任意时间开 始,也可以做任意多次。所有的工作给付的报酬都是一致的。同时,有 $ S $ 个课 程可以参加,我们认为今天是第 $ 0 $ 天,第 $ i $ 个课程在第 Mi 天开始,持续时间 为 $ Li $ 天,课程结束之后能力值会变为 $ Ai $ 。现在 $ Mark $ 的能力值为 $ 1 $ 。$ Mark $ 只 能做工作到第 $ T $ 天(因为那是飞船起飞的日子)。 他想知道期限内他最多可以做多少件工作,好决定未来的打算。于是他找到 了 $ applepi $ 。でも、$ applepi $ は彼女と一緒に楽しむことが大切だ,所以这个任务 就交给你了。

    输入格式

    第一行包含三个空格分隔的整数 $ T,S,N $ 。 之后 $ S $ 行,每行三个整数 $ M,L,A $ ,描述一个课程。 之后 $ N $ 行,每行两个整数 $ C,D $ ,描述一件工作。

    输出格式

    一个整数,表示 $ Mark $ 最多可以做多少件工作。

    样例输入

      10 1 2 3 2 5 4 1 1 3
    

    样例输出

      6
    

    样例解释

    第 $ 0 $ 天至第 $ 2 $ 天做第二件工作 $ 1 $ 次, 第 $ 3 $ 天至第 $ 4 $ 天参加课程,能力值变为 $ 5 $ 。然后第 $ 5 $ 天至第 $ 9 $ 天做第一件
    工作 $ 5 $ 次。 第 $ 10 $ 天 $ Mark $ 不可以继续做工作了。所以 $ Mark $ 最多做 6 次工作。

    数据范围与约定

    对于 $ 20 % $ 的数据,$ T,S,N≤10 $ 。 对于 $ 50% $ 的数据,$ T,N≤1000 $ 。 对于 $ 100% $ 的数据,$ S≤100,M,L≤10000,A≤100。N≤10000,C≤100, D≤10000,T≤10000 $ 。

    题解

    • 动态规划,定义 $ f[i][j] $ 代表在i时间,能力值为j的最多工作次数。
    • 对应最后三种选择:
    • ①不作为 $ f[i][j]=f[i-1][j] $ ,
    • ②上课 $ f[i][j]=f[ $ 上课前一个时刻 $ ][ $ 任意 $ ] $ ,
    • ③做工作 $ f[i][j]=f[i-p[j]][j]+1 (p[j] $ 为能力值 $ le j $ 的工作一次的最短用时 $ )$ 。
    • 对于②可以在预处理出$ k[i][j] $ 在i时刻结束,能力值达到j的课程的最晚开始时间。$ dp $ 过程中处理出 $ g[i]=max{f[i][j]} $。
    • $ g[t] $ 即为答案。
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int t,s,n,p[105],g[10005],f[10005][105],k[10005][105];
    int main(){
        memset(p,0x3f,sizeof(p));
        memset(f,-0x3f,sizeof(f));
        scanf("%d %d %d",&t,&s,&n);
        for(int m,l,a,i=1;i<=s;++i){
            scanf("%d %d %d",&m,&l,&a);
            k[m+l-1][a]=max(k[m+l-1][a],m);
        }
        for(int c,d,i=1;i<=n;++i){
            scanf("%d %d",&c,&d);
            for(int j=c;j<=100;++j)
                p[j]=min(p[j],d);
        }
        f[0][1]=0; 
        for(int i=1;i<=t;++i)
            for(int j=1;j<=100;++j){
                f[i][j]=f[i-1][j];
                if(k[i-1][j]) f[i][j]=max(f[i][j],g[k[i-1][j]]);
                if(i-p[j]>=0) f[i][j]=max(f[i][j],f[i-p[j]][j]+1);
                g[i]=max(g[i],f[i][j]);
            }
        printf("%d",g[t]);
        return 0;
    }
    

    树洞

    $ (holes.pas/c/cpp) $

    原题: jzoj4896 / CH Round #72 - NOIP 夏季划水赛 (没有找到链接)

    题目描述

    在一片栖息地上有 $ N $ 棵树,每棵树下住着一只兔子,有 $ M $ 条路径连接这些 树。更特殊地是,只有一棵树有 $ 3 $ 条或更多的路径与它相连,其它的树只有 $ 1 $ 条或 $ 2 $ 条路径与其相连。换句话讲,这些树和树之间的路径构成一张 $ N $ 个点、 $ M $ 条边的无向连通图,而度数大于 $ 2 $ 的点至多有 $ 1 $ 个。 近年以来,栖息地频繁收到人类的侵扰。兔子们联合起来召开了一场会议, 决定在其中 $ K $ 棵树上建造树洞。当危险来临时,每只兔子均会同时前往距离它 最近的树洞躲避,路程中花费的时间在数值上等于距离。为了在最短的时间内让 所有兔子脱离危险,请你安排一种建造树洞的方式,使最后一只到达树洞的兔子 所花费的时间尽量少。

    输入格式

    第一行有 $ 3 $个整数 $ N,M,K $ ,分别表示树(兔子)的个数、路径数、计划 建造的树洞数。 接下来 $ M $ 行每行三个整数 $ x,y $ ,表示第 $ x $ 棵树和第 $ y $ 棵树之间有一条路径相 连。$ 1 le x,y le ,x≠y, $ 任意两棵树之间至多只有 $ 1 $ 条路径。

    输出格式

    一个整数,表示在最优方案下,最后一只到达树洞的兔子所花费的时间。

    样例输入

      5 5 2 1 2 2 3 3 1 1 4 4 5 
    

    样例输出

      1 
    

    数据范围与约定

    对于 $ 20 % $ 的数据,$ 1 ≤  n ≤ 10 $ 。 对于另外 $ 30 % $ 的数据,每棵树至多与 $ 2 $ 条路径相连。
    对于另外 $ 30 % $ 的数据,保证存在一种最优解,使与 $ 3 $ 条或更多路径相连的树 上一定建造了树洞。
    对于 $ 100 % $ 的数据,$ 1 ≤ n ≤ 2000,n-1<=m<=n*(n-1)/2 $ 。

    题解

    • 二分答案。

    • 枚举距离特殊点最近的建造的树洞是哪一个,记为 $ X $ 。

    • 在图中删除能够在二分的时间内到达该树洞 $ X $ 的所有点。

    • 此时图变为若干条独立的链,直接求最少需要的树洞数。

    • 公式为 $ (n-X)/2*X $ 向上取整。

    • 代表了对于一条链,每 $ 2*X+1 $ 段就会有一个树洞。

    • 在所有枚举的情况中取最小值,与 $ K $ 比较确定二分范围变化。

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<vector>
    using namespace std;
    #define maxn 2005
    #define inf 1e9+7
    vector<int>E[maxn];
    int n,m,k,deg[maxn],root,ans;
    int dis[maxn];
    inline void bfs(int st){
    	memset(dis,-1,sizeof(int)*(n+1)); queue<int>q;
    	q.push(st); dis[st]=0;
    	while(!q.empty()){
    		int u=q.front(); q.pop();
    		for(int i=0;i<E[u].size();++i)
    			if(dis[E[u][i]]==-1){
    				dis[E[u][i]]=dis[u]+1;
    				q.push(E[u][i]);
    			}
    	}
    }
    int len;
    bool vis[maxn];
    void dfs(int u){
    	vis[u]=1; ++len;
    	for(int i=0;i<E[u].size();++i)
    		if(!vis[E[u][i]]) dfs(E[u][i]);
    }
    bool check(int x){
    	int nowans=inf;
    	for(int u=1;u<=n;++u){
    		bfs(u);
    		int res=0;
    		if(dis[root]>x) continue;
    		memset(vis,0,sizeof(bool)*(n+1));
    		for(int i=1;i<=n;++i) if(dis[i]<=x) vis[i]=1;
    		for(int i=1;i<=n;++i)
    			if(!vis[i]){
    				len=0;
    				dfs(i);
    				res+=(len-1)/(2*x+1)+1;
    			}
    		nowans=min(nowans,res+1);
    	}
    	return nowans<=k;
    }
    int main(){
    	freopen("holes10.in","r",stdin);
    	scanf("%d %d %d",&n,&m,&k);
    	for(int u,v,i=1;i<=m;++i){
    		scanf("%d %d",&u,&v);
    		E[u].push_back(v);
    		E[v].push_back(u);
    		++deg[u]; ++deg[v];
    		if(deg[u]>3){ root=i; }
    		if(deg[v]>3){ root=i; }
    	}
    	if(!root){
    		printf("%d",(n-k-1)/(2*k)+1);
    		return 0;
    	}
    	if(n==k){ puts("0"); return 0; }
    	int l=1,r=n;
    	while(l<=r){
    		int mid=l+r>>1;
    		if(check(mid)){ ans=mid; r=mid-1; }
    		else l=mid+1;
    	}
    	printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    (原)Lazarus 异构平台下多层架构思路、DataSet转换核心代码
    (学)新版动态表单研发,阶段成果3
    (学) 如何将 Oracle 序列 重置 清零 How to reset an Oracle sequence
    (学)XtraReport WebService Print 报错
    (原)三星 i6410 刷机 短信 无法 保存 解决 办法
    (原) Devexpress 汉化包 制作工具、测试程序
    linux下网络配置
    apache自带ab.exe小工具使用小结
    Yii::app()用法小结
    PDO使用小结
  • 原文地址:https://www.cnblogs.com/PotremZ/p/Test20180719.html
Copyright © 2011-2022 走看看