(vp训练)Educational Codeforces Round 71 (Rated for Div. 2) A-D

A:

显然,面包一样,肉贵的优先做

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e5+7;
 
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
 
 
 
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int t;
	  cin>>t;
	while(t--)
	{
		int b,p,f,h,c;
		cin>>b>>p>>f;
		cin>>h>>c;
		if(h<c)swap(h,c),swap(p,f);
		int x=min(b/2,p);
		b-=x*2;
		int ans=x*h;
		x=min(b/2,f);
		ans+=x*c;
		cout<<ans<<endl;
	 } 
	return 0;
}

B:

最多可2500次,把所有可以执行的操作都执行一遍,如果还不行,肯定就不行了

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 50+7;
 
 
int a[M][M];
int x[M*M],y[M*M],sz;
int vs[M][M];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int n,m;
  	cin>>n>>m;
  	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)cin>>a[i][j];
  	bool f=true;
  	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
  	{
  		if(a[i][j]==0)continue;
  		if(a[i+1][j]==1&&a[i][j+1]==1&&a[i+1][j+1]==1)
  			vs[i][j]=vs[i+1][j]=vs[i+1][j+1]=vs[i][j+1]=1,x[++sz]=i,y[sz]=j;  		
	}
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
	{
		if(a[i][j])
		{
			if(!vs[i][j])f=false;
		}
	}
	if(!f)cout<<-1<<endl;
	else
	{
		cout<<sz<<endl;
		for(int i=1;i<=sz;i++)cout<<x[i]<<" "<<y[i]<<endl;
	}
	return 0;
}

C:

刚开始把所有交叉口高度设为2,其余设为1.

发现:只有把两个交叉口中间的高度全提为1,才有可能使结果变小

花费少2个天然气管道,多nm-1个竖直管道,遍历取即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 2e5+7;
 
char s[M];
 
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int t;
  	cin>>t;
  	while(t--)
  	{
  		ll n,a,b;
  		cin>>n>>a>>b;
  		cin>>(s+1);
  		ll nm=0;
  		ll ans=(n+1)*b+n*a;
  		for(int i=1;i<=n;i++)
  		{
  			if(s[i]=='0')
  			{
  				if(nm)
  				{
  					ans+=a*2+(nm+1)*b;
  					nm=0;
				}
			}
			else nm++;
		}
		nm=0;bool f=false;
	//	cout<<ans<<endl;
		for(int i=1;i<=n;i++)
		{
			if(s[i]=='1')
			{
				if(f&&nm)
				{
				//	cout<<nm<<"  - "<<endl;
					if(-a*2+(nm-1)*b<0)
						ans+=-a*2+(nm-1)*b;
				}
				f=true;
				nm=0;
			}
			else nm++;
			
		}
		cout<<ans<<endl;
	}
	return 0;
}

D:

显然直接算好序列不好算。

我们用总序列个数减去ab其中一个不好的情况

ab其中一个不好等于:a不好+b不好-ab同时不好。

前两个很好算直接乘法原理。

第三个:

先把a排序,a中相同数字可以任意交换,在b中进行排序(a相同数字)。

如果b最终是升序,则存在a不好b不好的情况。

在a相同数字的情况下,且b相同数字,的区间,对可以任意交换。

也是乘法原理。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 3e5+7;
const int mod = 998244353 ;
struct node{
	int a,b;
}p[M];
int a[M],b[M];
bool cmp(node a,node b)
{
	return a.a<b.a;
}
ll fac[M];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int n;
  	cin>>n;
  	fac[0]=1;
  	for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
  	for(int i=1;i<=n;i++)
  		cin>>a[i]>>b[i],p[i]=node{a[i],b[i]};
	sort(a+1,a+1+n);
	sort(b+1,b+1+n);
	ll ans=0;//序列为坏的个数 
	ll tp=1;int pr=1;
	for(int i=2;i<=n+1;i++)
	{
		if(a[i]!=a[i-1])
		{
			tp=fac[i-1-pr+1]*tp%mod;
			pr=i;
		}
	}
	pr=1;
	ans=(ans+tp)%mod;
	tp=1;
	for(int i=2;i<=n+1;i++)
	{
		if(b[i]!=b[i-1])
		{
			tp=fac[i-1-pr+1]*tp%mod;
			pr=i;
		}
	}
	ans=(ans+tp)%mod;
	//下面求ab同时为坏的情况 
  	sort(p+1,p+1+n,cmp);
	for(int i=1;i<=n;i++)b[i]=p[i].b;
	pr=1;
	for(int i=2;i<=n+1;i++)
	{
		if(p[i].a!=p[i-1].a)
		{
			sort(b+pr,b+i);
			pr=i;
		}
	}
	bool f=true;
	for(int i=2;i<=n;i++)
		if(b[i]<b[i-1])f=false;
//	cout<<ans<<"  -- "<<f<<endl;
	if(f)
	{
		tp=1;pr=1;
		for(int i=2;i<=n+1;i++)
		{
		//	cout<<p[i].a<<"  "<<b[i]<<"===  "<<endl;
			if(p[i].a!=p[i-1].a)
			{
				int br=pr;
			//	cout<<br<<"  "<<i<<endl;
				for(int j=pr+1;j<=i;j++)
				{
					if(b[j]!=b[j-1]||j==i)
					{
					//	cout<<j<<" ==  "<<br<<"  "<<j-1-br+1<<endl;
						tp=tp*fac[j-1-br+1]%mod;
						br=j;
					}
				}
				pr=i;
			}
		//	cout<<tp<<"  - "<<endl;
		}
		ans=(ans+mod-tp)%mod;
	}
	ans=(fac[n]-ans+mod)%mod;
	cout<<ans<<endl;
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值