2018.01.29【NOIP普及组】模拟赛D组

111 篇文章 0 订阅
76 篇文章 0 订阅

今天-_-,比赛感觉好难啊!

JZOJ NO.1 【2018.1.29普及组模拟】NOIP

首先如何求原来的方案数呢?

=这里写图片描述
然后怎样求加p后的个数呢?再加上增加的个数
对于N而言,增加的为在N后I的个数。
对于I而言,增加的为在I后N的个数。
O再来一遍枚举求=这里写图片描述


代码如下

#include <cstdio>
#include <algorithm>
using namespace std;
unsigned long long ans; int ansn,anso,ansi,sn,si;
int a[100001],b[100001]; int n; char s[100001]; 
//a[i]求在1—i N的个数 b[i]求在i-n I的个数
int main(){
	freopen("noip.in","r",stdin);
	freopen("noip.out","w",stdout);
	scanf("%d\n",&n); gets(s);
	for (int i=0;i<n;i++) if (s[i]=='I') si++;//先提前算i的个数
	for (int i=0;i<n;i++){
		if (s[i]=='N') sn++;a[i]=sn;
		if (s[i]=='I') si--;b[i]=si;//减去
		if (s[i]=='O') ans+=a[i]*b[i],ansn+=si,ansi+=sn;
	}
	for (int i=0;i<n;i++)anso=max(anso,a[i]*b[i]);
	ans+=max(anso,max(ansn,ansi));
	printf("%llu",ans);
	return 0;
}

JZOJ NO.2 【2018.1.29普及组模拟】小麦高度

分析

首先最容易想到的就是如果种类<=2就退出,否则smart先操作,sarah操作得了(liao)便操作。(50分代码)


代码

#include <cstdio>
#include <algorithm>
#include <map>
using namespace std;
int a[100001],n,sum;
map<int,int>uk;
int main(){
	freopen("wheat.in","r",stdin);
	freopen("wheat.out","w",stdout);
	scanf("%d",&n);
	for (int i=1;i<=n;i++){
	 scanf("%d",&a[i]);
	 if (!uk[a[i]]) sum++;
	 uk[a[i]]++;
	} sort(a+1,a+1+n);
	if (sum<=2) puts("Sarah");
	while (sum>2){
		int i;
		for (i=1;a[1]==a[i];i++);
		uk[a[1]]--; uk[a[i]]++;
		if (!uk[a[1]]) sum--; a[1]=a[i];
		int k=1;
		for (i=2;i<=n;i++) if (a[k]>a[i]) swap(a[k],a[i]),k=i;
		if (sum<=2) puts("Smart");
		if (sum>2){
			for (i=n;a[n]==a[i];i--);
			uk[a[n]]--; uk[a[i]]++;
			if (!uk[a[n]]) sum--; a[n]=a[i];
			int k=n;
			for (i=n-1;i>=1;i--) if (a[k]<a[i]) swap(a[k],a[i]),k=i;
		    if (sum<=2) puts("Sarah");
		}
	} 
	int k=a[1]; printf("%d",a[1]);
	for (int i=2;i<=n;i++)
		if (k!=a[i]) k=a[i],printf(" %d",a[i]);
	if (n==1) printf(" 1");
	return 0;
}

这道题我是超时了。然后改进后代码如下!
就是用桶先排序,然后用个数优化。


AC代码

#include <cstdio>
#include <algorithm>
using namespace std;
struct z{int cou,num;}q[100001];
int a[100001]; int n,l=1,x,r,sum;
int main(){
	freopen("wheat.in","r",stdin);
	freopen("wheat.out","w",stdout);
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d",&x),a[x]++;//桶
	for (int i=1;i<=100000;i++) if (a[i]){q[++r].cou=a[i];q[r].num=i;}//个数和高度
	if (r-l+1<3) printf("Sarah\n%d %d",q[l].num,q[r].num);//如果不能开始就不玩了。
	if (r-l+1<3) return 0;
	while (r-l+1>=3){
		x=min(q[l].cou,q[r].cou);//最小值节省时间
		q[l].cou-=x; q[r].cou-=x;
		q[l+1].cou+=x; q[r-1].cou+=x;
		if (!q[l].cou) l++;//如果不能操作往里走
		if (!q[r].cou) r--;//it too
	}
	if (q[l].cou>q[r].cou) printf("Smart\n%d %d",q[l].num,q[r].num);//个数大说明他先结束
	else printf("Sarah\n%d %d",q[l].num,q[r].num);
	return 0;
}

JZOJ NO.3 【2018.1.29普及组模拟】铺设地板

分析

贪心+搜索


代码如下

#include <cstdio>
using namespace std;
int n,m; char c[101][101];
int ask(int x,int y){   
    int i;
    for (i=0;i<5;i++) 
    if ((c[x][y-1]!='A'+i)&&(c[x][y+1]!='A'+i)&&(c[x-1][y]!='A'+i)&&(c[x+1][y]!='A'+i)) 
return i;//四周没有这个字母
}
bool check(int x,int y,int l,int t){
return ((!c[x][y+l])&&(!c[x+l][y])&&(t+'A'!=c[x+l][y-1])//右边没填,下面没填,上面没有影响
        &&(t+'A'!=c[x-1][y+l])&&(t<=ask(x,y+l)));//左边没有影响,当前为最小的字母
}
void fill(int x,int y){
int t,a,l;
if (c[x][y]) return; t=ask(x,y); c[x][y]='A'+t;//最小值
a=(n-x)<(m-y)?n-x:m-y;
for (l=1;l<=a&&check(x,y,l,t);l++) c[x][y+l]='A'+t;//正方形扩张
for (int i=x;i<=x+l-1;i++)
for (int j=y;j<=y+l-1;j++) c[i][j]='A'+t;//填充
}
int main(){
freopen("floor.in","r",stdin);
freopen("floor.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (!c[i][j]) fill(i,j);//如果没有填过
for (int i=1;i<=n;i++) puts(c[i]+1);
return 0;
}

JZOJ NO.4 【2018.1.29普及组模拟】邮票

分析

其实它就是求一种邮票面额需要多少张。
所以说就用完全背包求出每种面额的方案数,然后再判断它是否符合k张以内。


代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,k,v,a[21],f[11001],sum,ans;
int main(){
	memset(f,0x7f,sizeof(f));
	freopen("stamp.in","r",stdin);
	freopen("stamp.out","w",stdout);
	scanf("%d%d",&n,&k); f[0]=0;//0是没有方案的
	for (int i=1;i<=n;i++) scanf("%d",&a[i]),v=max(v,k*a[i]);//最大计算量就为k*max(a[i])
	for (int i=1;i<=n;i++)
	for (int j=0;j<=v;j++)
	f[j+a[i]]=min(f[j]+1,f[j+a[i]]);//完全背包
	for (int j=1;j<=v;j++){
		if (f[j]<=k) sum++;//如果它符合增加
		else sum=0;//否则清零
		ans=max(ans,sum);//计算最大值
	}
	printf("%d",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值