zoukankan      html  css  js  c++  java
  • [JSOI2010]解题报告+2010~2011小结

    [JSOI2010~2011]小结

    有一些题目还没写,大概就是考了DP,一些数据结构,还有组合数学和图论这些东西,其实主要是思维难度比较大,比如挖宝藏的问题转化和怎么简便的转移,这些都要在平时多训练,提高思维能力

    [JSOI2010]旅行

    题解

    [JSOI2010]找零钱的洁癖

    乱搞,我写的是bfs+贪心

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    int x,n,a[53],an[500003],num[500003];
    map<int,int>mp;
    int ask1()
    {
    	int sum=x,ans=0;
    	for(int i=n;i>=1;i--)
    		if(a[i]!=0)
    			ans+=sum/a[i],sum-=sum/a[i]*a[i];
    	if(sum!=0)
    		return 1e18;
    	return ans;
    }
    int ask2()
    {
    	int hd=0,tl=1;
    	while(hd<tl)
    	{
    		hd++;
    		for(int i=1;i<=n;i++)
    		{
    			tl++,an[tl]=an[hd]+1;
    			if(tl>=200000)
    				return 1e18;
    			if(num[hd]<x)
    				num[tl]=num[hd]+a[i];
    			else
    				num[tl]=num[hd]-a[i];
    			if(num[tl]==x)
    				return an[tl];
    			if(mp[num[tl]]==1)
    				tl--;
    			mp[num[tl]]=1;
    		}
    	}
    	return 1e18;
    }
    signed main()
    {
    	scanf("%lld",&x);
    	while(scanf("%lld",&a[n+1])!=EOF)
    		n++;
    	sort(a+1,a+n+1);
    	mp[0]=1;
    	if(x==0)
    		cout<<0;
    	else
    		cout<<min(ask1(),ask2());
    	return 0;
    }
    

    [JSOI2010]挖宝藏

    我们可以先把问题转化一下,发现要挖到某一个宝藏,实际上就是往上取一个倒三角,那么我们可以把每个点都投影到一个区间上去,而且每一个区间都对应唯一的一个点

    然后设(dp[i])表示必选第(i)个区间的最大收益,考虑如果选了(i)区间,那么被完全包含的区间是必须要选的,直接把这些区间的收益算到(i)里面,往前枚举(j)转移,如果无交集就直接转移,如果有但是不是包含关系就要暴力去掉他们的交集,如果有包含关系就直接跳过

    然后注意一下细节就好了

    #include<bits/stdc++.h>
    using namespace std;
    struct node
    {
    	int l1,r1,p1,p2,bl;
    }a[1003];
    int n,x,y,now,sum,ans,dp[1003];
    int ask(int l,int r)
    {
    	return (r-l+2)*(r-l+2)/4;
    }
    int cmp(node nx,node ny)
    {
    	if(nx.r1!=ny.r1)
    		return nx.r1<ny.r1;
    	return nx.l1<ny.l1;
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d%d%d",&x,&y,&a[i].p1);
    		a[i].l1=x+y+1,a[i].r1=x-y-1,a[i].p2=0,a[i].bl=ask(a[i].l1,a[i].r1);
    	}
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    			if(a[j].l1>=a[i].l1&&a[j].r1<=a[i].r1)
    				a[i].p2+=a[j].p1;
    	sort(a+1,a+n+1,cmp);
    	for(int i=1;i<=n;i++)
    	{
    		dp[i]=a[i].p2-a[i].bl,now=1,sum=0;		
    		for(int j=1;j<i;j++)
    		{
    			if(a[j].r1<a[i].l1)
    				dp[i]=max(dp[i],dp[j]+a[i].p2-a[i].bl);
    			if(a[j].l1<a[i].l1&&a[j].r1>=a[i].l1)
    			{
    				while(now<=i&&a[now].r1<=a[j].r1)
    				{
    					if(a[now].l1>=a[i].l1)
    						sum+=a[now].p1;
    					now++;
    				}
    				dp[i]=max(dp[i],dp[j]+a[i].p2-a[i].bl-(sum-ask(a[i].l1,a[j].r1)));
    			}
    		}
    		ans=max(ans,dp[i]);
    	}
    	cout<<ans;
    	return 0;
    }
    

    [JSOI2010]排名

    手玩了好久才搞出了策略......round3的题目好毒瘤啊,这道题还算是相对简单的

    可以很显然的发现,这道题需要拓扑排序,第二问很简单,每次取能取到的,最大的就行了,用堆维护一下即可

    第二问稍微复杂一丢丢,我的做法是先DFS一遍,预处理这个点往后扩展的最小的点,设点(x)(minn[x]),然后每次取能取到的,(minn[x])最小的就行了,也是用堆维护

    #include<bits/stdc++.h>
    using namespace std;
    int n,a[200003],chu[200003],minn[200003],num[200003];
    vector<int>l[200003];
    struct node
    {
    	int x;
    	bool operator < (const node &nx)const
    	{
    		return minn[nx.x]<minn[x];
    	}
    }p,txt;
    priority_queue<node>q;
    struct node1
    {
    	int x1;
    	bool operator < (const node1 &nx)const
    	{
    		return nx.x1>x1;
    	}
    }p1,txt1;
    priority_queue<node1>q1;
    void dfs(int x)
    {
    	for(int j=0;j<l[x].size();j++)
    	{
    		dfs(l[x][j]);
    		minn[x]=min(minn[x],minn[l[x][j]]);
    	}
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    		if(a[i]!=0)
    			l[a[i]].push_back(i),chu[i]++;
    		minn[i]=i;
    	}
    	for(int i=1;i<=n;i++)
    		if(chu[i]==0)
    		{
    			dfs(i);
    			p.x=i,p1.x1=i,q.push(p),q1.push(p1);
    		}
    	for(int i=1;i<=n;i++)
    	{
    		p=q.top(),q.pop(),num[p.x]=i;
    		for(int j=0;j<l[p.x].size();j++)
    			txt.x=l[p.x][j],q.push(txt);
    	}
    	for(int i=1;i<=n;i++)
    		cout<<num[i]<<" ";
    	cout<<endl;
    	for(int i=1;i<=n;i++)
    	{
    		p1=q1.top(),q1.pop(),num[p1.x1]=i;
    		for(int j=0;j<l[p1.x1].size();j++)
    			txt1.x1=l[p1.x1][j],q1.push(txt1);
    	}
    	for(int i=1;i<=n;i++)
    		cout<<num[i]<<" ";
    	cout<<endl;
    	return 0;
    }
    
    
  • 相关阅读:
    bzoj4282 慎二的随机数列
    bzoj2839 集合计数
    bzoj1735 [Usaco2005 jan]Muddy Fields 泥泞的牧场
    bzoj3732 Network
    Kruskal重构树
    bzoj1568 [JSOI2008]Blue Mary开公司
    bzoj4576 [Usaco2016 Open]262144
    p2522 [HAOI2011]Problem b
    bzoj2463 谁能赢呢
    p4301 [CQOI2013]新Nim游戏
  • 原文地址:https://www.cnblogs.com/dzice/p/12247221.html
Copyright © 2011-2022 走看看