1. 程式人生 > >【codeforces】Codeforces Round #523 (Div. 2)

【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的滿足題意的方案數;

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;
}