• 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;
    }
    
  • 相关阅读:
    好消息,不用替换文件,凯立德能用了
    开心网外挂开发之 XML序列化于反序列化
    开心网外挂开发之 Singleton 单件模式应用
    开心网外挂开发之 开篇
    新买的雷柏1800无线套装
    新年好!!!!!!!!!!!!!!!!!!!!!!!
    恩,我还在写代码
    VS2019安装MSDN离线文档
    xaf使用非持久化类(nonpersistent)来展示lookuplist和展示树结构
    My Record Series: (1.2) Windows Phone 7 Launchers and Choosers
  • 原文地址:https://www.cnblogs.com/PotremZ/p/Test20180719.html
Copyright © 2020-2023  润新知