2017 10.25 NOIP模拟赛
Posted 日拱一卒 功不唐捐
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2017 10.25 NOIP模拟赛相关的知识,希望对你有一定的参考价值。
期望得分:100+40+100=240
实际得分:50+40+20=110
T1 start取了min没有用,w(゚Д゚)w O(≧口≦)O
T3 代码3个bug :数组开小了,一个细节没注意,手抖打错变量。。。
细节处理很重要啊!!!!
贪心,按结束时间排序
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define N 100001 struct node { int t,s; }e[N]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-\'0\'; c=getchar(); } } bool cmp(node p,node q) { return p.s>q.s; } int main() { freopen("manage.in","r",stdin); freopen("manage.out","w",stdout); int n; read(n); for(int i=1;i<=n;i++) read(e[i].t),read(e[i].s); sort(e+1,e+n+1,cmp); int now=2e9,start; for(int i=1;i<=n;i++) { start=min(now,e[i].s); now=start-e[i].t; } if(now>=0) printf("%d",now); else printf("-1"); }
设f[i] 表示 前i种珠子的排列方案
sum[i] 表示前i种珠子的前缀和
cnt[i] 表示第i种珠子的个数
因为第i种珠子的最后一个一定要在第i+1种珠子的最后一个之前
所以 到第i种珠子,第i种的最后一个一定在sum[i]位置上
所以还剩sum[i]-1个位置,还剩cnt[i]-1个珠子
所以 f[i]=f[i-1]*C(sum[i]-1,cnt[i]-1)
可以理解为 在sum[i]-1 个位置上选了cnt[i]-1个位置之后,剩下的位置就是把原来f[i-1]的每一种方案再塞进去
#include<cstdio> #include<iostream> using namespace std; #define N 100001 #define mod 998244353 int cnt[N],sum[N]; int fac[N*5],inv[N*5]; int f[N]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-\'0\'; c=getchar(); } } int Pow(int a,int b) { int r=1; for(;b;a=1ll*a*a%mod,b>>=1) if(b&1) r=1ll*a*r%mod; return r; } int getC(int a,int b) { return 1ll*fac[a]*inv[b]%mod*inv[a-b]%mod; } int main() { freopen("qiang.in","r",stdin); freopen("qiang.out","w",stdout); int n; read(n); for(int i=1;i<=n;i++) read(cnt[i]),sum[i]=sum[i-1]+cnt[i]; fac[0]=inv[0]=1; int tot=sum[n]; for(int i=1;i<=tot;i++) fac[i]=1ll*fac[i-1]*i%mod,inv[i]=Pow(fac[i],mod-2); f[1]=1; for(int i=2;i<=n;i++) f[i]=1ll*f[i-1]%mod*getC(sum[i]-1,cnt[i]-1)%mod; printf("%d",f[n]); }
考场上我是真的不会,~~~~(>_<)~~~~
40分大爆搜
#include<cstdio> #include<cstring> #include<iostream> using namespace std; #define N 100001 int n,tot; bool flag1; int sum[N]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-\'0\'; c=getchar(); } } void init() { read(n); for(int i=1;i<=n;i++) read(sum[i]),tot+=sum[i]; if(tot<=15) flag1=true; } namespace solve1 { int mx[16]; int ans=0; void dfs(int x,int tmp[16]) { if(x==tot+1) { ans++; return; } for(int i=1;i<=n;i++) if(tmp[i]) { if(tmp[i]==1) { for(int j=1;j<i;j++) if(!tmp[j] && mx[j]>x && mx[j]!=-1) return; for(int j=i+1;j<=n;j++) if(!tmp[j] && mx[j]<x && mx[j]!=-1) return; } tmp[i]--; int last=mx[i]; mx[i]=x; dfs(x+1,tmp); tmp[i]++; mx[i]=last; } } void work() { int rest[16]; for(int i=1;i<=n;i++) rest[i]=sum[i]; memset(mx,-1,sizeof(mx)); dfs(1,rest); printf("%d",ans); } } int main() { freopen("qiang.in","r",stdin); freopen("qiang.out","w",stdout); init(); if(flag1) solve1 :: work(); else printf("%d\\n",20001024); }
20%的数据:Q*N暴力枚举
另外30%的数据:
因为每个函数最多覆盖10个元素,而且保证每个位置只修改一次
所以最多进行10^6 次 单个的修改
用vector记录下每个元素对哪些函数有影响
用线段树维护 函数的和
修改的时候 枚举 这个元素有影响的所有函数,一个一个的在线段树里改
查询直接区间求和
100%的数据:
树状数组+分块
树状数组里记录每个元素的值
把数组分为根号n块,
cnt[i][j]记录 第i块内,第j个元素使用的次数
用 差分+前缀和 即可得到这个数组
用tot[i]记录第i块的函数和
修改的时候,直接修改tot,修改树状数组中的元素
查询的时候,一个块里的直接用tot,凑不成一个块的暴力在树状数组里查
代码3部分均有
#include<cmath> #include<cstdio> #include<vector> #include<iostream> #define lowbit(x) x&-x using namespace std; #define N 100001 typedef long long LL; int n; int a[N];LL sum[N]; int L[N],R[N]; bool flag2=true; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-\'0\'; c=getchar(); } } void init() { read(n); for(int i=1;i<=n;i++) read(a[i]),sum[i]=sum[i-1]+a[i]; for(int i=1;i<=n;i++) { read(L[i]); read(R[i]); if(R[i]-L[i]>10) flag2=false; } } namespace solve2 { vector<int>v[N]; LL tot[N<<2]; LL ans; void build(int k,int l,int r) { if(l==r) { tot[k]=sum[R[l]]-sum[L[l]-1]; return; } int mid=l+r>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); tot[k]=tot[k<<1]+tot[k<<1|1]; } void change(int k,int l,int r,int pos,int w) { if(l==r) { tot[k]+=w; return; } int mid=l+r>>1; if(pos<=mid) change(k<<1,l,mid,pos,w); else change(k<<1|1,mid+1,r,pos,w); tot[k]=tot[k<<1]+tot[k<<1|1]; } void query(int k,int l,int r,int opl,int opr) { if(l>=opl && r<=opr) { ans+=tot[k];return; } int mid=l+r>>1; if(opl<=mid) query(k<<1,l,mid,opl,opr); if(opr>mid) query(k<<1|1,mid+1,r,opl,opr); } void pre() { for(int i=1;i<=n;i++) for(int j=L[i];j<=R[i];j++) v[j].push_back(i); build(1,1,n); } void work() { pre(); int m,ty,l,r; int w,s; read(m); while(m--) { read(ty); read(l); read(r); if(ty==1) { w=r-a[l]; a[l]=r; s=v[l].size(); for(int i=0;i<s;i++) change(1,1,n,v[l][i],w); } else { ans=0; query(1,1,n,l,r); printf("%I64d\\n",ans); } } } } namespace solve1 { LL tot[N]; void pre() { for(int i=1;i<=n;i++) tot[i]=sum[R[i]]-sum[L[i]-1]; } void work() { pre(); int m,ty,l,r,w; LL ans; read(m); while(m--) { read(ty); read(l); read(r); if(ty==1) { w=r-a[l]; a[l]=r; for(int i=1;i<=n;i++) if(L[i]<=l && R[i]>=l) tot[i]+=w; } else { ans=0; for(int i=l;i<=r;i++) ans+=tot[i]; printf("%I64d\\n",ans); } } } } namespace solve3 { int siz,mx; int id[N],cnt[520][N+1]; unsigned long long tot[520],ans; LL c[N]; void add(int x,int w) { while(x<=n) { c[x]+=w; x+=lowbit(x); } } LL query(int x) { LL t=0; while(x) { t+=c[x]; x-=lowbit(x); } return t; } void pre() { siz=sqrt(n); for(int i=1;i<=n;i++) id[i]=(i-1)/siz+1; mx=(n-1)/siz+1; int l,r; for(int i=1;i<=mx;i++) { l=(i-1)*siz+1; r=min(i*siz,n); for(int j=l;j<=r;j++) { cnt[i][L[j]]++,cnt[i][R[j]+1]--; tot[i]+=sum[R[j]]-sum[L[j]-1]; } for(int j=1;j<=n;j++) cnt[i][j]+=cnt[i][j-1]; } for(int i=1;i<=n;i++) add(i,a[i]); } void out(unsigned long long x) { if(x/10) out(x/10); putchar(x%10+\'0\'); } void work() { pre(); int m,ty,l,r,w; int bl,br,tl,tr; read(m); while(m--) { read(ty); read(l); read(r); if(ty==1) { w=r-a[l]; a[l]=r; add(l,w); for(int i=1;i<=mx;i++) tot[i]+=1ll*cnt[i][l]*w; } else { ans=0; bl=(l-1)/siz+1; br=(r-1)/siz+1; tl=bl*siz; tr=(br-1)*siz+1; for(int i=l;i<=min(r,tl);i++) ans+=query(R[i])-query(L[i]-1); for(int i=bl+1;i<br;i++) ans+=tot[i]; if(bl!=br) for(int i=tr;i<=r;i++) ans+=query(R[i])-query(L[i]-1); out(ans); printf("\\n"); } } } } int main() { freopen("sum.in","r",stdin); freopen("sum.out","w",stdout); init(); if(n<=1000) solve1 :: work(); else if(flag2) solve2 :: work(); else solve3 :: work(); }
以上是关于2017 10.25 NOIP模拟赛的主要内容,如果未能解决你的问题,请参考以下文章