今天-_-,比赛感觉好难啊!
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);
}