zoukankan      html  css  js  c++  java
  • [1018NOIP模拟赛]

    题目描述 Description###

    精灵王国要同侵略 $ Bzeroth $ 大陆的地灾军团作战了。
    众所周知,精灵王国有 (N) 座美丽的城市,它们以一个环形排列在$ Bzeroth$ 的大陆上。为了补充军需,王国财政部决定从这$ N $ 座城市的商人们腰包中征用物资,其中第$ i $ 座城市的商人们共可以提供 $ A[i] $ 单位的物资。当征粮队征集物资的时候,他们发现一件出乎意料的事情:如果他们征集了第 (i) 座城市的物资,那么与第 $i $座城市相邻的两座城市($1 $ 号城市与 (N) 号城市相邻)里的商人都会逃跑,即征粮队不能再到这两座城市征集物资。财政部得知这一消息后迅速召开了会议,决定让精灵王国最好的工程师——你,来设计出最优的征集方案,使得联军能够征集到的物资尽可能多。

    输入描述 Input Description###

    第一行一个正整数$ N $ 。
    第二行$ N $ 个正整数,第 i 个数为$ A[i] $ 。

    输出描述 Output Description###

    输出最优情况下征集到的物资总和。

    样例输入 Sample Input###

    5 2 3 4 5 5

    样例输出 Sample Output###

    9
    

    数据范围及提示 Data Size & Hint###

    测试数据编号 数据范围 其他限制
    1 - 5 2 ≤ N ≤ 20
    6 - 7 2 ≤ N ≤ 2501
    8 - 9 2 ≤ N ≤ 152501 所有 $ A[i] $均相等
    10 2 ≤ N ≤ 152501
    对于 100%的数据:$1 ≤ A[i] ≤ 10^9 $ 。

    之前的一些废话###

    没有废话

    题解###

    环形灭虫子,先考虑直线情况, $ dp[i][0] $ 表示第i个不选的最大收益,$ dp[i][1] $ 表示第i个选的最大收益,转移的话是(dp_{i,1}=max exttt{{}0,dp_{i-1,0} exttt{}}+a_i),(dp_{i,0}=max exttt{{}dp_{i-1,1},dp_{i-1,0} exttt{}};)
    若是环形的话,则强行令端头选,端头不选各DP一次。

    代码###

    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    typedef long long LL;
    #define mem(a,b) memset(a,b,sizeof(a))
    typedef pair<int,int> PII;
    inline int read()
    {
    	int x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    	return x*f;
    }
    const int maxn=152510,oo=2147483647;
    int n,a[maxn];
    LL dp[maxn][2],ans;
    int main()
    {
    	n=read();
    	for(int i=1;i<=n;i++)a[i]=read();
    	dp[1][1]=a[1];dp[1][0]=-oo;
    	for(int i=2;i<=n;i++)
    	{
    		dp[i][1]=max(0ll,dp[i-1][0])+a[i];
    		dp[i][0]=max(dp[i-1][0],dp[i-1][1]);
    	}
    	ans=dp[n][0];
    	dp[1][1]=-oo;dp[1][0]=0;
    	for(int i=2;i<=n;i++)
    	{
    		dp[i][1]=max(0ll,dp[i-1][0])+a[i];
    		dp[i][0]=max(dp[i-1][0],dp[i-1][1]);
    	}
    	ans=max(ans,max(dp[n][0],dp[n][1]));
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    总结###

    没有总结

    题目描述 Description###

    每一个生活在$ Bzeroth $ 大陆的精灵都知道,若想毁灭他们深爱的这片土地,必须要先摧毁守护 $ Bzeroth $ 大陆的$ N $ 个能量核心。
    这 $ N $ 个能量核心由诸神修建的 $ M $ 条秩序神链沟通,其中第$ i $ 条秩序神链沟通了第$ u_i $ 和第 $ v_i $个核心,稳定程度为 $ w_i$ 。最开始,这 $ N $ 个能量核心是连通的(即任意两个能量核心均能通过神链直接或间接沟通)。地灾军团的军师黑袍得知,他们可以摧毁若干神链使得这 $ N $ 个能量核心 恰好被分成两个连通块,从而削弱 $ Bzeroth $ 大陆的防卫能量。由于被摧毁后的防卫能量等于未被摧毁的神链的稳定程度之和,所以他找到了精灵王国最好的工程师,同时也是地灾军团潜伏在 $ Bzeroth $ 大陆多年的间谍——你,来设计出最优的方案,使得未被摧毁的神链的稳定程度之和最小。

    输入描述 Input Description###

    第一行为 2 个整数 $ N $ 、$ M $ 。
    接下来 M 行每行三个正整数 $ u_i $ 、$ v_i $ 、 $ w_i $ 。

    输出描述 Output Description###

    输出最优情况下未被摧毁的神链的稳定程度之和。

    样例输入 Sample Input###

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

    样例输出 Sample Output###

    6
    

    数据范围及提示 Data Size & Hint###

    测试数据编号 数据范围 其他限制
    1 - 5 2 ≤ N、M ≤ 15
    6 - 7 2 ≤ N、M ≤ 152501 2 ≤ N ≤ 15
    8 2 ≤ N、M ≤ 152501 M = N - 1
    9 2 ≤ N、M ≤ 152501 M = N
    10 2 ≤ N、M ≤ 152501
    对于 100%的数据:$ 1 ≤ u_i、v_i≤ N,1 ≤ w_i ≤ 10^9 $ 。

    之前的一些废话###

    没有废话

    题解###

    随便试一两个图就发现答案是原图的最小生成树-最小生成树上的最大权值边

    代码###

    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    typedef long long LL;
    #define mem(a,b) memset(a,b,sizeof(a))
    typedef pair<int,int> PII;
    typedef pair<int,PII> PIP; 
    #define X first
    #define Y second
    #define MP make_pair
    inline int read()
    {
    	int x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    	return x*f;
    }
    const int maxn=152510,oo=2147483647;
    int n,m,a,b,c,f[maxn];
    LL sum,MAX;
    PIP E[maxn];
    int getf(int x){return f[x]==x ? x : f[x]=getf(f[x]);}
    void merge(int a,int b)
    {
    	int x=getf(a),y=getf(b);
    	if(x!=y)f[x]=y;
    }
    int main()
    {
    	n=read();m=read();
    	for(int i=1;i<=n;i++)f[i]=i;
    	for(int i=1;i<=m;i++)a=read(),b=read(),c=read(),E[i]=MP(c,MP(a,b));
    	sort(E+1,E+m+1);
    	for(int i=1;i<=m;i++)
    	{
    		int u=E[i].Y.X,v=E[i].Y.Y;
    		if(getf(u)!=getf(v))
    		{
    			sum+=E[i].X;
    			MAX=max(MAX,(LL)E[i].X);
    			merge(u,v);
    		}
    	}
    	printf("%lld
    ",sum-MAX);
    	return 0;
    }
    
    

    总结###

    没有总结

    题目描述 Description###

    精灵心目中亘古永恒的能量核心崩溃的那一刻,$ Bzeroth $ 大陆的每个精灵都明白,他们的家园已经到了最后的时刻。
    就在这危难关头,诸神天降神谕,传下最终兵器——潘少拉魔盒。然而当精灵们准备打开魔盒时,魔盒的守护灵出现在精灵们面前:“如果你们想要拯救世界,必须要先解决这个困难的问题:定义一个 N 阶数列 A 为神奇数列当且仅当对所有$ 2 ≤i ≤ N - 1 $ ,都有 $ A_i-1 + A_i+1 ≥ 2 × A_i $ 。现在有一个$ N $ 阶正整数列$ B $ ,请计算将 $ B $ 数列均匀随机打乱之后,得到的数列是神奇数列的概率 $ P $ 。你只需要输出 $ P × (N!) mod 998244353 $ 的结果即可。(显然 $ P × (N!) $ 一定是个整数)。”

    输入描述 Input Description###

    第一行为 1 个正整数 $ N $。
    第二行为 N 个正整数 $ A_i $。

    输出描述 Output Description###

    输出 $ P × (N!) mod 998244353 $ 的结果。

    样例输入 Sample Input###

    4 1 2 1 3

    样例输出 Sample Output###

    8
    

    数据范围及提示 Data Size & Hint###

    对于 50%的数据:3 ≤ N ≤ 10。
    对于 80%的数据:3 ≤ N ≤ 20。
    对于 100%的数据:3 ≤ N ≤ 40,$ 1 ≤A_i ≤ 10^9 $ 。

    之前的一些废话###

    没有废话

    题解###

    发现当且仅当A数组是一个下凸函数时才满足题意
    考试时候写的是80分,排个序是肯定的,然后我们确定了最小值,开始往两边依次递增的填数,用 $ 2^n $ 枚举在左边的数,然后判一判是否合法。最后算出总方案数乘以最小数个数的阶乘即可。正解在这基础上稍微改一下即可,往两边插值的时候判断能否插入只与左右两端最大值次大值有关,设计状态 $ dp[i][j][k][l] $ 表示当前序列最左边两个数分别是$ a_i $ 和$ a_j $ ,最右边两个数分别是$ a_k $ 和$ a_l $ 的合法序列数,转移显然。复杂度 (O(n^4))

    代码###

    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    typedef long long LL;
    #define mem(a,b) memset(a,b,sizeof(a))
    typedef pair<int,int> PII;
    typedef pair<int,PII> PIP;
    const int MOD=998244353,maxn=42;
    inline int read()
    {
    	int x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    	return x*f;
    }
    int n,a[maxn],sum=1,jc[maxn],dp[maxn][maxn][maxn][maxn],ans;
    int main()
    {
        n=read(); 
        jc[0]=1;
        for(int i=1;i<=n;i++)a[i]=read(),jc[i]=((LL)jc[i-1]*(LL)i)%MOD;
        sort(a+1,a+n+1);
        for(int i=2;i<=n;i++)
    	{
    		if(a[i]!=a[i-1])break;
    		sum++;
    	}
    	for(int i=sum+1;i<=n;i++)a[i-sum+1]=a[i];
    	dp[1][0][1][0]=1;
    	n=n-sum+1;
    	for(int i=1;i<=n;i++)
    	    for(int j=0;j<i;j++)
    		    for(int k=1;k<=n;k++)
    			    for(int l=0;l<k;l++) 
    			    {
    			    	int pos=max(i,k)+1;
    			    	if(pos==n+1){ans=(ans+dp[i][j][k][l])%MOD;continue;}
    			    	if(2*a[i]<=a[pos]+a[j] || i==1)dp[pos][i][k][l]=(dp[pos][i][k][l]+dp[i][j][k][l])%MOD;
    			    	if(2*a[k]<=a[pos]+a[l] || k==1)dp[i][j][pos][k]=(dp[i][j][pos][k]+dp[i][j][k][l])%MOD;
    			    }
    	printf("%d
    ",((LL)ans*(LL)jc[sum])%MOD);		    
    	return 0;
    }
    

    总结###

    设计DP状态时要充分考虑哪些状态是真正需要用到的。

  • 相关阅读:
    TSQL 字符串前加 N 是什么意思
    SQL语句修改字段默认值
    Clustering Technologies On Windows Server 2008 R2
    sql 修改列名及表名
    Capture screenshots on Mac 在Mac下截图
    极限编程(XP,eXtreme Programming)
    zookeeper安装(单机版)
    linux备份用户权限
    Dubbo管控台安装(zookeeper单机版)
    linux查看IP
  • 原文地址:https://www.cnblogs.com/FYH-SSGSS/p/7693057.html
Copyright © 2011-2022 走看看