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状态时要充分考虑哪些状态是真正需要用到的。

  • 相关阅读:
    Java实现 LeetCode 833 字符串中的查找与替换(暴力模拟)
    Java实现 LeetCode 833 字符串中的查找与替换(暴力模拟)
    Java实现 LeetCode 833 字符串中的查找与替换(暴力模拟)
    Java实现 LeetCode 832 翻转图像(位运算)
    Java实现 LeetCode 832 翻转图像(位运算)
    Java实现 LeetCode 832 翻转图像(位运算)
    Java实现 LeetCode 831 隐藏个人信息(暴力)
    Java实现 LeetCode 831 隐藏个人信息(暴力)
    Java实现 LeetCode 831 隐藏个人信息(暴力)
    how to use automapper in c#, from cf~
  • 原文地址:https://www.cnblogs.com/FYH-SSGSS/p/7693057.html
Copyright © 2011-2022 走看看