【codeforces】Codeforces Round #523 (Div. 2)

目录

【B. Views Matter】贪心

【C. Multiplicity】dp+滚动数组

【D. TV Shows】贪心


【B. Views Matter】

 题目链接:https://codeforces.com/contest/1061/problem/B

【题意】有一堆块,给出每个的高度ai,给出俯视图和右视图,从原来的堆中最多可以取出多少块使得俯视图和右视图均保持不变。并且题中规定物体是不受重力影响的,即拿掉之后是不会有物块进行移动的。

【分析】贪心。将物块按高度由高到低排序,记录初始高度。ans初值是n,即要先满足俯视图。k由1开始,如果当前k<当前块高度,那么k++,一直到k达到最大高度n,此时右视图已经满足,break掉就好。

【代码】

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int maxn=1e5+10;
int a[maxn];

int main()
{
	ll n,m;scanf("%lld%lld",&n,&m);
	ll sum=0;
	for(ll i=0;i<n;i++)
	{
		scanf("%lld",&a[i]);
		sum+=a[i];
	}
	sort(a,a+n);
	ll ans=n,k=1;
	for(int i=0;i<n;i++)
	{
		if(k<=a[i])k++;
		if(k>a[n-1])break;
	}
	ans=ans+a[n-1]-k+1;
	printf("%lld\n",sum-ans);
	return 0;
}

【C. Multiplicity】dp+滚动数组

题目链接:https://codeforces.com/contest/1061/problem/C

【题目】长度为n的序列,移除一些元素之后使之成为“good array”(对于其下标i总满足a[i]%i==0)

【分析】dp[i][j]:选择前i个元素组成的序列中长度为j的满足题意的方案数;

扫描二维码关注公众号,回复: 4337419 查看本文章

dp[i][j]=\begin{cases} dp[i-1][j]+dp[i-1][j-1] & \text{ if } a[i]\%j=0\\ dp[i-1][j] & \text{ else } \end{cases}

因为题上数据范围比较大,1e5,所以开二维数组会爆内存的

所以,要用到滚动数组———是一种节省空间的办法,时间上貌似没有什么优势,多用于DP中

上述递推关系式中,第一维中每次只用到了i和i-1,我们压缩第一维,

那么dp[x]中的x就相当于上式中的j,得下式:

dp[x]=dp[x]+dp[x-1];

dp[x]表示长度为x的合法子序列的个数;

每次dp[x]在未更新前存的相当于是上面递推式中的dp[i-1][j],dp[x-1]就相当于dp[i-1][j-1],理解一下— —

【代码】

#include<bits/stdc++.h>
using namespace std;

const int maxn=1e6+5;
const int mod=1e9+7;
typedef long long ll;

ll dp[maxn],a[maxn];
vector<int>v[maxn];

int main()
{
	ll n;scanf("%lld",&n);
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
	for(int i=1;i<=n;i++)
	{
		ll now=sqrt(a[i]);
		for(int j=1;j<=now;j++)
		{
			if(a[i]%j==0)
			{
				v[i].push_back(j);
				if(a[i]!=j*j) v[i].push_back(a[i]/j);//存2次,但防止了有两个相同因子的数进2次 
			}
		}
		sort(v[i].begin(),v[i].end()); 
	}
	dp[0]=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=v[i].size()-1;j>=0;j--)
		{
			int now=v[i][j];
			dp[now]+=dp[now-1];
			dp[now]%=mod;
		}
	} 
	ll ans=0;
	for(int i=1;i<=n;i++)ans+=dp[i];
	ans%=mod;
	printf("%lld\n",ans);
	return 0;
}

【D. TV Shows】

题目链接:https://codeforces.com/contest/1061/problem/D

【题意】给出n个节目的开始时间与结束时间,给出租每台TV的花费以及租了之后每分钟的花费。求放映完所有节目的最小花费。

【分析】贪心。先把n个节目排序,是否再租一台电脑取决于这段时间的花费与x的大小。用set和map,map存同一结束时间的节目数,当某个值为0时表示这个点结束的节目都已放映完。set存每个节目的结束时间。

emmm感觉是个思维题,暂时可能不会想到这么做,代码也理解了好一会...

【代码】参考https://blog.csdn.net/qq_39826163/article/details/84649678

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn=1e5+5;
const ll mod=1e9+7;

struct node{
	ll l,r;
}a[maxn];
bool cmp(node x,node y)
{
	return x.l!=y.l?x.l<y.l:x.r<y.r;
}

set<ll>s;
set<ll>::iterator it;
map<ll,int>mp;

int main()
{
	int n; ll x,y;
	scanf("%d%lld%lld",&n,&x,&y);
	for(int i=0;i<n;i++)scanf("%lld%lld",&a[i].l,&a[i].r);
	sort(a,a+n,cmp);
	ll ans=0;
	s.insert(a[0].r);
	mp[a[0].r]++;
	ans=(ans+x+y*(a[0].r-a[0].l)%mod)%mod;
	for(int i=1;i<n;i++)
	{
		it=s.lower_bound(a[i].l);//大于等于当前开始时间的结束时间 
		if(it==s.begin())//没找到 
		{
			ans=(ans+x+y*(a[i].r-a[i].l)%mod)%mod;
			mp[a[i].r]++;
		 } 
		else
		{
			it--;
			ll value=*it;
			if(a[i].l>value && y*(a[i].l-value)<=x)
			{
				mp[value]--;
				if(mp[value]==0)s.erase(value);
				ans=(ans+y*(a[i].r-value)%mod)%mod;
				mp[a[i].r]++;
			 } 
			else
			{
				ans=(ans+x+y*(a[i].r-a[i].l)%mod)%mod;
				mp[a[i].r]++;
			}
		}
		s.insert(a[i].r);
	}
	printf("%lld\n",ans);
	return 0;
}
 
 
 

猜你喜欢

转载自blog.csdn.net/qq_38735931/article/details/84639280