NOIP2017提高组 模拟赛19(总结)
来源:互联网 发布:centos 移除文件夹 编辑:程序博客网 时间:2024/05/22 03:32
NOIP2017提高组 模拟赛19(总结)
第一题 数组 (贪心)
【题目描述】
【解题思路】
若
【代码】
#include<cstdio>#include<algorithm>using namespace std;typedef long long ll;int n;ll s;int main(){ freopen("2006.in","r",stdin); freopen("2006.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) { int a; scanf("%d",&a); s+=a; } if(!(s%n)) printf("%d\n",n); else printf("%d\n",n-1); return 0;}
第二题 歌词 (AC自动机)
【题目描述】
【解题思路】
典型的AC自动机,不过空间有点悬(可以开map……)
用歌词建AC自动机(用歌建的话会MLE),用歌去匹配,每匹配到一个地方就标记加+1。最后dfs整棵fail树,将儿子的标记加到父亲上。最后输出每个歌词的匹配数(建AC自动机时,在记下最后一个单词在AC自动机的位置,歌词的匹配数就是AC自动机的位置的匹配数)。
【代码】
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;typedef long long ll;const int Ln=1800000;int n,m,root,cnt;int ne[Ln],to[Ln],h[Ln],tt;int q[Ln],kp[550];ll sum[Ln];char st[50050];struct data { int fail,fa,r[63]; } T[Ln];int gs(char ch){ if(ch=='-') return 62; if('0'<=ch && ch<='9') return ch-'0'; if('A'<=ch && ch<='Z') return ch-'A'+10; if('a'<=ch && ch<='z') return ch-'a'+10+26;}void addtrie(int bel){ int cl=strlen(st),now=root; for(int i=1;i<=cl;i++) { int cd=gs(st[i-1]); if(!T[now].r[cd]) { cnt++; T[cnt].fa=now; T[now].r[cd]=cnt; } now=T[now].r[cd]; } kp[bel]=now;}void addedge(int a,int b) { to[++tt]=b; ne[tt]=h[a]; h[a]=tt; }void buildfail(){ int head=1,tail=1; q[1]=root; while(head<=tail) { int fnow=q[head++]; for(int i=0;i<63;i++) if(T[fnow].r[i]) { int v=T[fnow].r[i]; int k=T[fnow].fail; bool flag=(fnow!=root); while(!T[k].r[i]) { if(k==root) { flag=0; break; } k=T[k].fail; } if(flag) T[v].fail=T[k].r[i]; else T[v].fail=root; q[++tail]=v; addedge(T[v].fail,v); } }}void dfs(int x,int fa){ for(int p=h[x];p;p=ne[p]) { int v=to[p]; dfs(v,x); sum[x]+=sum[v]; }}int main(){ freopen("2019.in","r",stdin); freopen("2019.out","w",stdout); scanf("%d",&n); tt=1; root=1; cnt=1; T[1].fail=1; T[1].fa=1; for(int i=1;i<=n;i++) { scanf("%s",st); addtrie(i); } buildfail(); scanf("%d",&m); for(int i=1;i<=m;i++) { scanf("%s",st); int cl=strlen(st); int now=root; for(int j=1;j<=cl;j++) { int yu=gs(st[j-1]); while(now!=root && (!T[now].r[yu])) now=T[now].fail; if(T[now].r[yu]) now=T[now].r[yu]; sum[now]++; } } dfs(root,root); for(int i=1;i<=n;i++) printf("%lld\n",sum[kp[i]]); return 0;}
第三题 旅行 (splay优化DP)
【题目描述】
【解题思路】
50%
记dp[i]为去了i个目的地,所花的最小天数。
可以知道dp[]一定是严格递增的。
若加入了景点[L,R]
那么设p为dp[p]>=L的最小下标。
dp[p]=min(dp[p],L);
∵dp[p]>=L ∴dp[p]=L;
设q为dp[q]>=R+1的最小下标。
j∈[p+1,q-1] dp[j]=min(dp[j],dp[j-1]+1);
∵dp[]一定是严格递增的。 ∴dp[j]>dp[j-1],dp[j]=dp[j-1]+1;
时间复杂度:O(n^2)
100%
可以发现:dp数组仅仅插入了一个值,把其中的一端集体+1并集体右移了一位,删除了末端的一位。
写个splay就好了。
插入的话就先找到该插入的位置(严格递增的,并不需要记是第几位),连边。
集体+1就打个懒惰标记,down下去。
删除的话就把它旋到末端,cut掉就行。
最后dfs整棵splay树,统计有几个是不为无穷大的。(一开始所有值为无穷大)
我写前驱后继写炸了,换了一种写法才A。(我也不知道为什么)
【代码】
#include<cstdio>#include<algorithm>using namespace std;typedef long long ll;const int oo=1e9+10;const int N=610050;int n,cnt,sum;struct tree{ tree *f,*c[2]; int val,lz; int d() { return (f->c[1]==this); } void sc(tree *x,int d) { (c[d]=x)->f=this; }} nil[N],*root,*stack[N];tree *newtree(int vg){ nil->val=nil->lz=0; nil->c[0]=nil->c[1]=nil->f=nil; nil[++cnt]=nil[0]; nil[cnt].val=vg; return nil+cnt;}void down(tree *x){ if(x==nil) return; if(x->lz!=0) { if(x->c[0]!=nil) { x->c[0]->lz+=x->lz; x->c[0]->val+=x->lz; } if(x->c[1]!=nil) { x->c[1]->lz+=x->lz; x->c[1]->val+=x->lz; } x->lz=0; }}void rotate(tree *x){ int d=x->d(); tree *y=x->f; y->sc(x->c[!d],d); if(y->f==nil) root=x,x->f=nil; else y->f->sc(x,y->d()); x->sc(y,!d);}void splay(tree *x){ int hy=1; stack[hy]=x; for(;stack[hy]->f!=nil;hy++) stack[hy+1]=stack[hy]->f; for(int i=hy;i>=1;i--) down(stack[i]); for(tree *y;x->f!=nil;) { y=x->f; if(y->f!=nil) (y->d()^x->d())?rotate(x):rotate(y); rotate(x); }}tree *build(int L,int R){ if(L>R) return nil; int Mid=(L+R)>>1; tree *ty=newtree(oo); ty->sc(build(L,Mid-1),0); ty->sc(build(Mid+1,R),1); return ty;}void cut(tree *x){ for(;;) { if(x->c[0]!=nil) { down(x->c[0]); rotate(x->c[0]); } else if(x->c[1]!=nil) { down(x->c[1]); rotate(x->c[1]); } else { x->f->sc(nil,x->d()); splay(x->f); return; } }}void dfs(tree *x){ down(x); if(x==nil) return; if(x->val>0 && x->val<oo) sum++; if(x->c[0]!=nil) dfs(x->c[0]); if(x->c[1]!=nil) dfs(x->c[1]);}void search(int dl){ tree *x,*now=root; while(now!=nil) { if(now->val>=dl) { x=now; now=now->c[0]; } else now=now->c[1]; down(now); } splay(x);}int main(){ freopen("2020.in","r",stdin); freopen("2020.out","w",stdout); scanf("%d",&n); root=newtree(0); root->sc(build(1,n),1); for(int i=1;i<=n;i++) { int dl,dr; scanf("%d%d",&dl,&dr); search(dl); root->val++; root->c[1]->val++; root->c[1]->lz++; tree *now=root->c[0]; while(now->c[1]!=nil) { down(now); now=now->c[1]; } down(now); now->sc(newtree(dl),1); splay(now->c[1]); search(dr+1); root->c[1]->val--; root->c[1]->lz--; cut(root); } sum=0; dfs(root); printf("%d\n",sum); return 0;}
- NOIP2017提高组 模拟赛19(总结)
- NOIP2017提高组模拟赛4 (总结)
- NOIP2017提高组模拟赛5 (总结)
- NOIP2017提高组模拟赛 7(总结)
- NOIP2017提高组模拟赛 8(总结)
- NOIP2017提高组模拟赛 9 (总结)
- NOIP2017提高组模拟赛 10 (总结)
- NOIP2017提高组 模拟赛13(总结)
- NOIP2017提高组 模拟赛15(总结)
- NOIP2017提高组 模拟赛16(总结)
- NOIP2017提高组 模拟赛17(总结)
- NOIP2017提高组 模拟赛18(总结)
- NOIP2017提高组 模拟赛20(总结)
- NOIP2017提高组 模拟赛21(总结)
- NOIP2017提高组 模拟赛23(总结)
- NOIP2017提高组 模拟赛24(总结)
- NOIP2017提高组 模拟赛 26(总结)
- NOIP2017提高组 模拟赛 27(总结)
- 策略模式与机制
- 前端经常遇到的一些面试题
- #Java 核心技术卷一阅读笔记# 第五章 继承
- 关于opencv常量错误
- 使用UICollectionView写公司的项目
- NOIP2017提高组 模拟赛19(总结)
- Excel,开启一键装逼模式
- LeetCode 674. Longest Continuous Increasing Subsequence
- 关于”算法工程师/机器学习工程师”的笔试和面试总结
- 视图和表的区别
- [linux]mac解除某个端口的占用
- 为什么苹果原装数据线容易破皮?怎么解决苹果数据线损坏问题
- maven生成war包的两种方式
- workqueue