2017.11.25【NOIP提高组】模拟赛A组
2017.11.25【NOIP提高组】模拟赛A组
T1 3467. 【NOIP2013模拟联考7】最长上升子序列(lis)
T2 3468. 【NOIP2013模拟联考7】OSU!(osu)
T3 3472. 【NOIP2013模拟联考8】匹配(match)
T1 有转移方程f[i]=max{f[j]}+1,a[j]<a[i]
可以用线段树+离散化维护这个方程,因为涉及以往状态可以用主席树维护
打太丑爆空间了
Code
1 #include<cstdio> 2 #include<cmath> 3 #include<cstring> 4 #include<algorithm> 5 #define fo(i,a,b) for(int i=a;i<=b;i++) 6 #define fd(i,a,b) for(int i=a;i>=b;i--) 7 #define fh(i,x) for(int i=head[x];i;i=next[i]) 8 typedef long long LL; 9 inline int max(int x,int y){return (x<y)?y:x;} 10 inline int min(int x,int y){return (x<y)?x:y;} 11 inline int read() { 12 int x=0,f=1;char ch=getchar(); 13 while(ch<'0'||ch>'9')f=(ch=='-')?-1:f,ch=getchar(); 14 while(ch>='0'&&ch<='9')x=x*10+(ch-'0'),ch=getchar();return f*x; 15 } 16 using namespace std; 17 const int N=500000+50; 18 int op[N],a[N],b[N],x[N],cnt1,now,ans,tot,ans1[N],q[N],tot1; 19 struct tree { 20 int l,r,mx; 21 tree *xl,*xr; 22 tree(){l=r=mx=0,xl=xr=NULL;} 23 void update() { 24 if(!xl&&!xr)return; 25 if(xl&&xr)mx=max(xl->mx,xr->mx); 26 else mx=(xl)?xl->mx:xr->mx; 27 } 28 int query(int L,int R) { 29 if(L>R)return 0; 30 if(l==L&&r==R)return mx; 31 int mid=(l+r)>>1; 32 int tx=0; 33 if(xl&&R<=mid)return xl->query(L,R); 34 if(xr&&l>mid)return xr->query(L,R); 35 else { 36 if(xl)tx=xl->query(L,mid); 37 if(xr)tx=max(tx,xr->query(mid+1,R)); 38 return tx; 39 } 40 } 41 void add(int p,int val) { 42 if(l==r){mx=val;return;} 43 int mid=(l+r)>>1; 44 tree *tl=xl,*tr=xr; 45 if(p<=mid) { 46 xl=new tree;if(tl)xl->xl=tl->xl,xl->xr=tl->xr; 47 xl->l=l,xl->r=mid,xl->add(p,val); 48 } else { 49 xr=new tree;if(tr)xr->xl=tr->xl,xr->xr=tr->xr; 50 xr->l=mid+1,xr->r=r,xr->add(p,val); 51 } 52 update(); 53 } 54 }*rt[N]; 55 int main() { 56 freopen("lis.in","r",stdin),freopen("lis.out","w",stdout); 57 int n=read(); 58 fo(i,1,n) { 59 op[i]=read(); 60 if(op[i])x[i]=read(); 61 else a[++cnt1]=b[cnt1]=read(); 62 } 63 sort(b+1,b+1+cnt1);int cnt=unique(b+1,b+1+cnt1)-b-1; 64 fo(i,1,cnt1)a[i]=lower_bound(b+1,b+cnt+1,a[i])-b; 65 now=0,ans=0; 66 rt[0]=new tree,rt[0]->l=1,rt[0]->r=cnt; 67 fo(i,1,n) { 68 if(!op[i]) { 69 int t=0;tot1++; 70 if(rt[now])t=rt[now]->query(1,a[tot1]-1); 71 (rt[i]=new tree)->l=1,rt[i]->r=cnt; 72 if(rt[now])rt[i]->xl=rt[now]->xl,rt[i]->xr=rt[now]->xr; 73 rt[i]->add(a[tot1],t+1); 74 ans=max(ans,t+1); 75 q[i]=i,ans1[i]=ans; 76 now=i; 77 } 78 if(op[i]) { 79 now=x[i],ans=ans1[x[i]],rt[i]=rt[x[i]]; 80 q[i]=x[i],ans1[i]=ans; 81 } 82 } 83 fo(i,1,n)printf("%d\n",ans1[i]); 84 return 0; 85 }
T2 如果把连续的一段 1,和这段两边的 0 作为一个整体,那么这些就是相互独立的。 分别计算每一个即可
用Dp优化这个做法
dp[i][0] = ∑ (1 − 𝑎[𝑘]) ∏ 𝑎[𝑘] 𝑖 𝑘+1 𝑖−1 𝑘=0 ,dp[i][1]表示∑ (𝑖 − 𝑘 − 𝑖−1 𝑘=0 1)(1 − 𝑎[𝑘]) ∏ 𝑎[𝑘] 𝑖 𝑘+1 ,dp[i][2]
表 示 ∑ (i − k − 1) 2 (1 − 𝑎[𝑘]) ∏ 𝑎[𝑘] 𝑖 𝑘+1 𝑖−1 𝑘=0 ,dp[i][3] 表 示 ∑ (i − k − 1) 3 (1 − 𝑎[𝑘]) ∏ 𝑎[𝑘] 𝑖 𝑘+1 𝑖−1 𝑘=0
dp[i][0]=(dp[i-1][0]+1-a[i-1])*a[i];
dp[i][1]=(dp[i-1][0]+dp[i-1][1]+1-a[i-1])*a[i]
dp[i][2]=(dp[i-1][0]+2dp[i-1][1]+dp[i-1][2]+1-a[i-1])*a[i]
dp[i][3]=(dp[i-1][0]+3dp[i-1][1]+3dp[i-1][2]+dp[i-1][3]+1-a[i-1])*a[i]
ans=∑ 𝑑𝑝[𝑖][3] ∗ (1 − 𝑎[𝑖 − 1]) 𝑛 𝑖=1
我们定义 a[0]=a[n+1]=0
Code
1 #include<cstdio> 2 using namespace std; 3 double f,t2,t1,P; 4 int N; 5 int main() 6 { 7 freopen("osu.in","r",stdin),freopen("osu.out","w",stdout); 8 scanf("%d",&N); 9 for(int i=0;i<N;i++) { 10 scanf("%lf",&P); 11 f+=P*(3*(t2+t1)+1); 12 t2=P*(t2+2*t1+1); 13 t1=P*(t1+1); 14 } 15 printf("%.1f\n",f); 16 }
T3 显然是一道Dp题,那刚学的ac自动机练练手
f[i][j][s]表示构造到了第i位,j是ac自动机上的位置,s是目前完成的字串状态(二进制压缩)
枚举M集合里的元素,转移十分简单
Code
1 #include<cstdio> 2 #include<cmath> 3 #include<cstring> 4 #include<algorithm> 5 #define fo(i,a,b) for(int i=a;i<=b;i++) 6 #define fd(i,a,b) for(int i=a;i>=b;i--) 7 #define fh(i,x) for(int i=head[x];i;i=next[i]) 8 typedef long long LL; 9 typedef double DB; 10 using namespace std; 11 inline int max(int x,int y){return (x<y)?y:x;} 12 inline int min(int x,int y){return (x<y)?x:y;} 13 inline int read() { 14 int x=0,f=1;char ch=getchar(); 15 while(ch<'0'||ch>'9')f=(ch=='-')?-1:f,ch=getchar(); 16 while(ch>='0'&&ch<='9')x=x*10+(ch-'0'),ch=getchar(); 17 return f*x; 18 } 19 const int maxn=100+50,mo=1e9+7; 20 int n,M,K,len,tot; 21 int f[maxn][maxn<<2][1<<8],d[3*maxn],a[35],cnt[35]; 22 char s[35]; 23 struct AC{int son[26],fail,bz;}tr[maxn<<2]; 24 void add(int x,int i,int id) { 25 int num=s[i]-'a'; 26 if(!tr[x].son[num])tr[x].son[num]=++tot; 27 if(i!=len)add(tr[x].son[num],i+1,id); 28 else tr[tr[x].son[num]].bz=(1<<(id-1)); 29 } 30 void make_fail() { 31 int l=0,r=1; 32 while(l<r) { 33 int x=d[++l]; 34 fo(p,1,M) { 35 int t=a[p]; 36 if(tr[x].son[t]) { 37 int v=tr[x].son[t]; 38 if(!x)tr[v].fail=0; 39 else tr[v].fail=tr[tr[x].fail].son[t]; 40 tr[v].bz|=tr[tr[v].fail].bz; 41 d[++r]=v; 42 } else tr[x].son[t]=tr[tr[x].fail].son[t]; 43 } 44 } 45 } 46 int main() { 47 n=read(),K=read(); 48 fo(i,1,K)scanf("%s",s+1),len=strlen(s+1),add(0,1,i); 49 int x=read(); 50 scanf("%s",s+1); 51 fo(i,1,x)if(!cnt[s[i]-'a'])cnt[s[i]-'a']=1,a[++M]=s[i]-'a'; 52 make_fail(); 53 f[0][0][0]=1; 54 fo(i,0,n-1)fo(j,0,tot)fo(k,0,(1<<K)-1) 55 if(f[i][j][k])fo(p,1,M) { 56 int next=tr[j].son[a[p]],finsh=k|tr[next].bz; 57 f[i+1][next][finsh]=(f[i+1][next][finsh]+f[i][j][k])%mo; 58 } 59 int ans=0; 60 fo(i,0,tot)ans=(ans+f[n][i][(1<<K)-1])%mo; 61 printf("%d\n",ans); 62 return 0; 63 }