• 【日记】1.1


    1.1

    贪心

    1.1283E:New Year Parties

    题意:有n个人,分别在1-n之间的点上,每个人最多往左或往右走一个格子,问走完之后最少占据格子和最多占据格子数分别是多少。

    思路:贪心。最多:考虑每个位置怎么被占据,首先判断前面一个格子,如果还有剩的就拉过来,再看当前格子,如果有就占据,再看右边的格子,如果有就拉过来。可以用反证法说明这么做是最优的。

    最少:考虑每个位置的数怎么丢出去。vis数组记录每个位置被占据的情况。如果前一个位置必须被占据,就丢到上一个。否则就丢到下一个位置,并占据下一个位置。可以用反证法说明这么做是最优的。

    #include<bits/stdc++.h>
    using namespace std;
    #define LL long long
    #define mid ((l+r)>>1)
    #define db(x) cout<<#x<<":"<<x<<endl;
    const int M=2e5+20,P=1e9+7;
    struct TTTT{
    	int n,num1[M],num2[M],vis[M];
    	void init(){
    		scanf("%d",&n);
    		for(int i=1;i<=n;++i){
    			int c;
    			scanf("%d",&c),++num1[c];
    		}
    		for(int i=1;i<=n;++i)
    			num2[i]=num1[i];
    	}
    	void run(){
    		init();
    		int ans=0;
    		for(int i=1;i<=n;++i){
    			if (num2[i]==0||vis[i])
    				continue;
    			if(vis[i-1])
    				num2[i]=0;
    			else
    				vis[i+1]=1,++ans;
    		}
    		printf("%d ",ans);
    		ans=0;
    		if (num1[1])
    			--num1[1],++ans;
    		for(int i=1;i<=n;++i)
    			if (num1[i-1])
    				--num1[i-1],++ans;
    			else if (num1[i])
    				--num1[i],++ans;
    			else if (num1[i+1])
    				--num1[i+1],++ans;
    		if (num1[n])
    			--num1[n],++ans;
    		printf("%d
    ",ans);
    	}
    }TTT;
    int main(){
    	TTT.run();
    	return 0;
    }
    

    DP

    1.1271D:Portals

    题意:你一开始有k个兵,要顺次打n个城堡,打完城堡之后不会损失兵。每个城堡有a,b,c三个参数,表示必须拥有>=a个兵才能打下来,打完之后可以获得b个兵,之后如果分出来1个兵占领这个城堡,那么就可以获得c点分数,如果不占领就不获得分数。

    这里还有一些神奇的portal,有u和v两个参数,表示当你站在u城堡的时候,可以传送一个兵到v去占领v。注意不可以连续传送,比如你站在4,不可以4-3再3-1,只能用所在城堡直接相连的portal。

    要求必须n个城堡全部打下来才可以,如果不能,输出-1,否则输出打完n个城堡之后可以获得的最大分数。

    思路:我是DP做法。首先不考虑portal,那么dp[i] [j]表示打完前i个城堡之后,还剩下j个兵的状态,能得到的最大分数。那么刷表即可,每一个状态可以有两种选择,打完留兵或者打完不留,dp[i] [j+b[i]]=max(当前, dp[i-1] [j]),dp[i] [j+b[i]-1]=max(当前, dp[i-1] [j]+c[i])。时间复杂度(O(nsum k))

    现在考虑portal。如果不占领第i个城堡,就不影响。利用贪心易知,如果要派兵占领第i个城堡,而且存在portal使得可以从之后的城堡j,k,l,……传送回来,那么选择之后城堡里面编号最大的那个往回传送一定是最优的。感性理解一下,留兵的唯一不利是有可能往前打的过程中兵不够打不了了,所以上述选择能够让那个本来直接留下的兵多打几轮(而且是尽可能多打了),再回来防守,所以肯定不会变差。

    所以现在走到第i个城堡之后,选择变多了,首先是是否在本地留兵,之后是往回传送几个兵。

    v[i]表示城堡i往回传送的目的地(可以看代码看具体意义)。那么还是贪心,肯定先选那些c值大的城堡传送,因此就先排序,再前缀和,就依次是往回传送1,2,3,4,5……个兵的最大获得的分数了。

    细节比较多,需要分类讨论一下,详见代码。

    时间复杂度不变,仍然是(O(nsum k)),只不过要注意,这里的dp[i] [j]不再是原来子问题了,即前i的城堡剩下j个兵的最大分数,这是因为已经贪心处理portal的原因。

    #include<bits/stdc++.h>
    using namespace std;
    #define LL long long
    #define mid ((l+r)>>1)
    #define db(x) cout<<#x<<":"<<x<<endl
    #define qmax(x,y) (x)=max((x),(y))
    const int M=5e3+50,P=1e9+7;
    int n,m,k,a[M],b[M],c[M],dp[M][M],pfrom[M];
    vector<int> v[M];
    struct cmp{
    	bool operator()(int x,int y){
    		return c[x]>c[y];
    	}
    };
    struct TTTT{
    	void init(){
    		scanf("%d%d%d",&n,&m,&k);
    		for(int i=1;i<=n;++i)
    			scanf("%d%d%d",&a[i],&b[i],&c[i]);
    		for(int i=1;i<=m;++i){
    			int j,k;
    			scanf("%d%d",&j,&k),pfrom[k]=max(pfrom[k],j);
    		}
    		for(int i=1;i<=n;++i)
    			if(pfrom[i])
    				v[pfrom[i]].push_back(i);
    	}
    	void run(){
    		init();
    		int kmin=k,kmax=k;
    		for(int i=1;i<=n;++i){
    			kmin=max(kmin,a[i]);
    			if (kmin>kmax){
    				printf("-1
    ");
    				return;
    			}
    			if (!v[i].empty()){
    				sort(v[i].begin(),v[i].end(),cmp());
    				v[i][0]=c[v[i][0]];
    				for(int k=1;k<v[i].size();++k)
    					v[i][k]=c[v[i][k]]+v[i][k-1];
    			}
    			for(int j=kmin;j<=kmax;++j){
    				qmax(dp[i][j+b[i]],dp[i-1][j]);
    				if (!v[i].empty())
    					for(int k=0;k<v[i].size()&&j+b[i]-k-1>=0;++k)
    						qmax(dp[i][j+b[i]-k-1],dp[i-1][j]+v[i][k]);
    				if (!pfrom[i]){
    					if (j+b[i]-1>=0)
    						qmax(dp[i][j+b[i]-1],dp[i-1][j]+c[i]);
    					if (!v[i].empty())
    						for(int k=0;k<v[i].size()&&j+b[i]-1-k-1>=0;++k)
    							qmax(dp[i][j+b[i]-1-k-1],dp[i-1][j]+c[i]+v[i][k]);
    				}
    			}
    			kmax+=b[i],kmin+=b[i]-v[i].size()-(!pfrom[i]?1:0);
    		}
    		int ans=0;
    		for(int i=kmin;i<=kmax;++i){
    			qmax(ans,dp[n][i]);
    		}
    		printf("%d
    ",ans);
    	}
    }TTT;
    int main(){
    	TTT.run();
    	return 0;
    }
    

    最后这个题好搞啊,写了好久。

  • 相关阅读:
    MVC的各个部分都有那些技术来实现?如何实现?
    JRE、JDK、JVM 及 JIT 之间有什么不同
    什么是竞态条件?举例说明
    【Spring】No converter found for return value of type: class java.util.ArrayList
    【Spring】org.springframework.web.context.ContextLoaderListen 报错
    【Spring】The matching wildcard is strict……
    【MySQL】目录、文件权限问题
    线程和锁
    【Git】Found a swap file by the name ".git/.MERGE_MSG.swp"
    【Maven】Mac 使用 zsh 后 mvn 命令就无效
  • 原文地址:https://www.cnblogs.com/diorvh/p/12129744.html
Copyright © 2020-2023  润新知