Educational Round 71 (Rated for Div. 2) A(简单贪心),B(简单模拟),C(简单DP),D(组合数+容斥),E(交互问题,分治),F(数据结构,分块)

G似乎有点难,估计鸽掉了。。

Contest:http://codeforces.com/contest/1207

A-There Are Two Types Of Burgers(简单贪心)

题目链接:http://codeforces.com/contest/1207/problem/A

题目大意:给出b个皮,p个牛肉,f个鸡肉,让你组装成利润最多的组合。牛肉包需要2皮+1牛肉,鸡肉堡需要2皮+1鸡肉。h是牛肉煲单价,c是鸡肉堡单价。

思路:贪心,[b/2]个汉堡,加和即可。

ACCode:

int n,p,f;
int h,c;
 
int main(){
	int T;scanf("%d",&T);
	while(T--){
		scanf("%d%d%d",&n,&p,&f);
		scanf("%d%d",&h,&c);
		n>>=1;
		int Ans=0;
		if(c>=h){//chichen is batter
			if(n>=f){//all chicken
				Ans+=f*c;
				n-=f;
			}
			else{//all bun
				Ans+=n*c;
				n=0;
			}
			if(n>=p){//all beef
				Ans+=p*h;
				n-=p;
			}
			else{//all bnn
				Ans+=n*h;
				n=0;
			}
		}
		else{
			if(n>=p){
				Ans+=p*h;
				n-=p;
			}
			else{
				Ans+=n*h;
				n=0;
			}
			if(n>=f){
				n-=f;
				Ans+=f*c;
			}
			else{
				Ans+=n*c;
				n=0;
			}
		}printf("%d\n",Ans);
	}
	
}

B-Square Filling(简单模拟)

题目链接:http://codeforces.com/contest/1207/problem/B

题目大意:给出一个(n*m)的0,1矩阵A。让你经过k次修改将一个全0的(n*m)矩阵B修改为A。每次修改一个2*2的范围。不能修改输出-1

思路:从左上角枚举即可,最后比较。

ACCode:

int A[MAXN][MAXN],B[MAXN][MAXN];
PII Ans[MAXN*MAXN];int tot;
int n,m;
 
int main(){
	while(~scanf("%d%d",&n,&m)){
		clean(B,0);
		for(int i=1;i<=n;++i){
			for(int j=1;j<=m;++j){
				scanf("%d",&A[i][j]);
			}
		}
		tot=0;
		for(int i=1;i<=n;++i){
			for(int j=1;j<=m;++j){
				if(A[i][j]&&A[i+1][j]&&A[i][j+1]&&A[i+1][j+1]){
					Ans[++tot]=make_pair(i,j);
					B[i][j]=B[i+1][j]=B[i][j+1]=B[i+1][j+1]=1;
				}
			}
		}
		int flag=1;
		for(int i=1;i<=n;++i){
			for(int j=1;j<=m;++j){
				if(A[i][j]!=B[i][j]){
					flag=0;break;
				}
			}
		}
		if(flag){
			printf("%d\n",tot);
			for(int i=1;i<=tot;++i) printf("%d %d\n",Ans[i].first,Ans[i].second);
		}
		else printf("-1\n");
	}
}

C-Gas Pipeline(简单DP)

题目链接:http://codeforces.com/contest/1207/problem/C

题目大意:给出一个01串,0代表该位置是路,1代表该位置是路口,是路的地方可以假设高为1的管子,路口的地方只能假设高为2的管子,问你将这个路线架设完管子的最小花费。架子b花费每单位,管子a花费每单位。

思路:只有两种状态,该点架设高为1||2的,在路口只能架设高为2的。很容易推出状态转移方程:

DP[i][1]=min(DP[i-1][1]+a+b,DP[i-1][2]+2*a+b);//i表示第i个路线,1表示高为1,

DP[i][2]=min(DP[i-1][1]+2*a+2*b,DP[i-1][2]+a+2*b);

最后约束一下路口时只能建造单位2的就好了就好了。

ACCode:

char S[MAXN];
ll DP[MAXN][3];
ll n,a,b;
 
int main(){
	int T;scanf("%d",&T);
	while(T--){
		scanf("%lld%lld%lld",&n,&a,&b);
		scanf("%s",&S);
//		for(int i=0;i<n;++i) printf("%c",S[i]);printf("\n");
		DP[0][1]=b;DP[0][2]=INF64;//
		for(int i=1;i<n;++i){
			if(S[i-1]=='0'&&S[i]=='0'){//可以设置单位1的高度 
				DP[i][1]=min(DP[i-1][1]+a+b,DP[i-1][2]+2*a+b);
				DP[i][2]=min(DP[i-1][1]+2*a+2*b,DP[i-1][2]+a+2*b);
			}
			else{//只能是单位2 
				DP[i][1]=INF64;
				DP[i][2]=min(DP[i-1][1]+2*a+2*b,DP[i-1][2]+a+2*b);
			}
//			printf("1=%lld 2=%lld\n",DP[i][1],DP[i][2]);
		}
		DP[n][1]=min(DP[n-1][1]+a+b,DP[n-1][2]+2*a+b);
//		DP[i][2]=min(DP[i-1][1]+2*a+2*b,DP[i-1][2]+a+2*b);
		printf("%lld\n",DP[n][1]);
	}
	
}

D- Number Of Permutations(组合数+容斥)

题目链接:http://codeforces.com/contest/1207/problem/D

题目大意:给出n对数(x,y)找出所有的不是坏序列的个数。坏序列的定义是:一个排列中,x不递减的是坏序列。y不递减的是坏序列,(x,y)都不递减的是坏序列。

思路:很明显的组合数+容斥,首先得到全排列S。A第一关键字的重复排列之积,B第二关键字的重复排列之积,AB双关键字的重复排列之积。最后判断一下是否存在BC。因此就是Ans=S-A-B+AB;
ACCode:

/*
共n!种组合 S 
第一关键字排序,第一关键字相同的得到组合数相加 B 
第二关键字排序,相同的组合数相加 C
双关键字,相同的 BC
 Ans=S-A-B+C
*/
PII A[MAXN];
ll Fac[MAXN];
int n;
 
int Cmp1(PII a,PII b){
	return a.first<b.first;
}
int Cmp2(PII a,PII b){
	return a.second<b.second;
}
int Cmp3(PII a,PII b){
	if(a.first==b.first) return a.second<b.second;
	return a.first<b.first;
}
void Intt(){
	Fac[0]=Fac[1]=1;
	for(ll i=2;i<MAXN;++i){
		Fac[i]=(i*Fac[i-1])%MOD;
	}
}
int main(){
	Intt();
	while(~scanf("%d",&n)){
		for(int i=1;i<=n;++i){
			scanf("%d%d",&A[i].first,&A[i].second);
		}sort(A+1,A+1+n,Cmp1);
		ll ans=Fac[n],B=1,C=1,BC=1;
		for(int i=1,j=1;j<=n;j=i){
			while(i<=n&&A[i].first==A[j].first) ++i;
			B=(B*Fac[i-j])%MOD;
		}sort(A+1,A+1+n,Cmp2);
		for(int i=1,j=1;j<=n;j=i){
			while(i<=n&&A[i].second==A[j].second) ++i;
			C=(C*Fac[i-j])%MOD;
		}sort(A+1,A+1+n);
		for(int i=1,j=1;j<=n;j=i){
			while(i<=n&&A[i].second==A[j].second&&A[i].first==A[j].first) ++i;
			BC=(BC*Fac[i-j])%MOD;
		}
		for(int i=2;i<=n;++i){
			if(A[i-1].second>A[i].second) BC=0;
		}
//		printf("ans=%lld B=%lld C=%lld BC=%lld\n",ans,B,C,BC);
		ans=(ans-B-C+BC+2ll*MOD)%MOD;
		printf("%lld\n",ans);
	}
	
	
}

E-XOR Guessing(交互问题,分治)

题目链接:http://codeforces.com/contest/1207/problem/E

题目大意:猜一个数x在[0,2^14-1]。有两次机会,每次询问100个数,随机挑一个回答x^a[i],让你得出x是多少

思路:将两次询问分成[0,2^7-1]和[2^7,2^14-1]区间,这样,第一次确定的前七位,第二次确定后六位。拼起来就好了。注意交互问题的输入输出形式。。Wa了好几发,缓冲区没清空。。。

ACCode:

int main(){
	int ans1,ans2,ans=0;
	cout<<"? 1";//printf("? 1");
	for(int i=2;i<=100;++i) cout<<" "<<i;cout<<endl;//printf(" %d",i);printf("\n");
	cin>>ans1;//scanf("%d",&ans1);//得到前六位的值 
	for(int i=(1<<14);i>=(1<<7);i>>=1){
		if(i&ans1){//这一位存在 
			ans|=i;
		}
	} 
	cout<<"? "<<(1<<7);//printf("? %d",(1<<7));
	for(int i=(1<<8),j=2;j<=100;i+=(1<<7),++j) cout<<" "<<i;cout<<endl;//printf(" %d",i);printf("\n");
	cin>>ans2;//scanf("%d",&ans2);
	for(int i=(1<<6);i>0;i>>=1){
		if(ans2&i){
			ans|=i;
		}
	}cout<<"! "<<ans<<endl;//printf("! %d\n",ans);
	fflush(stdout);
}

F-Remainder Problem(数据结构,分块)

题目链接:http://codeforces.com/contest/1207/problem/F

题目大意:给出一个[1,5e5]的数组,初始元素都为0,两种操作。1:x y a[x]+=y  2:x,y 求在[1,5e5]中找到所有a[i]的i%x==y的a[i]之和。

思路:分成两部分,sqrt(5e5),小的块维护一个Sum,大的块直接暴力求和即可。

对于Sum的维护,每次修改一个x位置的元素后,对于小部分,每个i只会对x%i产生影响(其他的取不到)。这里的i就是query里面的x.

ACCode:

/*
修改A[x]+=y
查询A[[1,5e5]%x==y]之和。 
每次修改,对于我们只用处理出 sqrt(5e5)的所有影响就好了
x对Sum的影响,每次修改一个x位置的y后直接对应的Sum[i][i%x]+=y 
查询x>sqrt(5e5)的时候,直接就可以暴力相加。否则直接输出答案即可 
*/
int A[MAXN];
int Sum[750][750];
int q;
 
int main(){
	while(~scanf("%d",&q)){
		clean(Sum,0);
		while(q--){
			int opt;scanf("%d",&opt);
			if(opt==1){//修改x的值+y 
				int x,y;scanf("%d%d",&x,&y);
				A[x]+=y;
				for(int i=1;i<750;++i) Sum[i][x%i]+=y;
			}
			else{//查询下标为[[1,5e5]%x]==y的数之和 
				int x,y;scanf("%d%d",&x,&y);
				if(x>=750){//直接加就好了 
					int ans=0;
					for(int i=y;i<=5e5;i+=x) ans+=A[i];
					printf("%d\n",ans);
				}
				else printf("%d\n",Sum[x][y]);
			}
		}
	}
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值