JSOI2015 Round2 Day2题解

来源:互联网 发布:钟南山 知乎 编辑:程序博客网 时间:2024/05/01 16:20

我先来开一个大坑,填完JSOI2014-15的题目(计算几何就嘿嘿嘿了),未来什么时候填完还不知道,心情好也许填的快,也许一轮省选后吧23333。

由于某些奇怪的原因,JSOI的题目好像都带着版权,所以不能放题目描述了,大家自己脑补吧。

T1:

T1本来是一道挺难的数学题,然而考场上你可以选择成为,暴力选手,人类智慧大师等等,答案就是很简单的2^(nk)。但是这个的正确性并不好证,我来口胡一下。首先那个n个元素显然是相互独立的,所以求出来答案之后直接来一个n次幂就好了,至于这个k是怎么来的,我们来画一个图。

这玩意显然形成了一个在左上角的黑色联通块,于是我们就得到了一条黑白的分界线,这条线一定从左下角出发,一直到右上角的边界,每步都有两种选择,所以就是2^k辣。

于是程序就是这辣鸡玩意

#include<cstdio>#include<cstring>#include<algorithm>#include<cstdlib>#include<iostream>#define mod 1000000007#define LL long longusing namespace std;int n,k;LL p;int fexp(int x,LL p){int ans=1;//cout<<p<<endl;for(;p;p>>=1,x=(1LL*x*x)%mod)if(p&1)ans=(1LL*ans*x)%mod;return ans;}void Work(){int ans;ans=fexp(2,p);printf("%d\n",ans);}void Init(){scanf("%d%d",&n,&k);p=1LL*n*k;}int main(){freopen("subset.in","r",stdin);freopen("subset.out","w",stdout);Init();Work();return 0;}

T2:

T2是一个很明显的分数规划模型啊,所以说直接二分答案然后单调队列搞一搞。

具体呢,就是令答案为p,那么(max(i,j)-min(i,j))/(j-i+k)>p

移项乱搞搞,就变成了max(i,j)-min(i,j)-p(j-i)>p*k

这个式子不好搞,我们可以强制令一端处是最大值,另一端是最小值,但是可能无法做到,所以做之前我们可以先用线段树跑一发长度为l和r的答案作为初值。

然后强制令左边为max,式子变成了Maxi+p*i-Minj-p*j>p*k,我们令新数列bi=ai+i*p,单调队列搞一搞就好了。


cqh老司机还提出了另外一种神奇(乱搞)的做法,二分答案,维护一个左端点,那么合法的点应该在一个直线和一次函数的上边,貌似有点抽象,反正就是这样

啊,那个阴影就是合法区,还是单调队列搞一搞,不过不需要去构造新数列辣

本校不懂的同学可以直接去问cqh本人辣。

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<cstdlib>#define maxn 50010using namespace std;int n,k,L,R;int a[maxn];struct Node{int l,r,mn,mx;}T[maxn<<2];void build(int i,int l,int r){int M=l+r>>1;T[i].l=l,T[i].r=r;if(l==r){T[i].mx=T[i].mn=a[l];return;}build(i<<1,l,M);build(i<<1|1,M+1,r);T[i].mx=max(T[i<<1].mx,T[i<<1|1].mx);T[i].mn=min(T[i<<1].mn,T[i<<1|1].mn);}int querymax(int i,int l,int r){int M=T[i].l+T[i].r>>1;int ans=0;if(l<=T[i].l&&r>=T[i].r)return T[i].mx;if(l<=M)ans=max(ans,querymax(i<<1,l,r));if(r>M)ans=max(ans,querymax(i<<1|1,l,r));return ans;}int querymin(int i,int l,int r){int M=T[i].l+T[i].r>>1;int ans=0x7f7f7f7f;if(l<=T[i].l&&r>=T[i].r)return T[i].mn;if(l<=M)ans=min(ans,querymin(i<<1,l,r));if(r>M)ans=min(ans,querymin(i<<1|1,l,r));return ans;}double b[maxn];int Q[maxn],bot,top;bool Check(double M){for(int i=1;i<=n;i++)b[i]=a[i]+M*i;Q[top=bot=1]=n;for(int i=n-L+1;i;i--){while(top<=bot&&Q[top]>=i+R)top++;if(b[i]-b[Q[top]]>=k*M)return true;while(top<=bot&&b[Q[bot]]>b[i+L-2])bot--;Q[++bot]=i+L-2;}for(int i=1;i<=n;i++)b[i]=a[i]-M*i;Q[top=bot=1]=n;for(int i=n-L+1;i;i--){while(top<=bot&&Q[top]>=i+R)top++;if(b[Q[top]]-b[i]>=k*M)return true;while(top<=bot&&b[Q[bot]]<b[i+L-2])bot--;Q[++bot]=i+L-2;}return false;}const double eps=1e-7;double solve(){double L=0,R=1000.0;while(R-L>eps){double M=(L+R)/2;if(Check(M))L=M;else R=M;}return L;}void Work(){double ans=0;build(1,1,n);for(int i=1;i<=n-L+1;i++)ans=max(ans,(double)(querymax(1,i,i+L-1)-querymin(1,i,i+L-1))/(L-1+k));for(int i=1;i<=n-R+1;i++)ans=max(ans,(double)(querymax(1,i,i+R-1)-querymin(1,i,i+R-1))/(R-1+k));ans=max(ans,solve());printf("%.4lf\n",ans);}void Init(){scanf("%d%d%d%d",&n,&k,&L,&R);for(int i=1;i<=n;i++)scanf("%d",&a[i]);}int main(){int T;freopen("gift.in","r",stdin);freopen("gift.out","w",stdout);scanf("%d",&T);while(T--){Init();Work();}return 0;}

T3:

T3不是模版题吗,模版题,模版。。。。

那你还错一发。。。

没什么好说的学过可持久化Trie的同学都会:

#include<cstring>#include<cstdio>#include<iostream>#include<algorithm>#include<cstdlib>#include<queue>#define maxn 100010using namespace std;struct Edge{int to,id;Edge *next;};Edge *E[maxn],Pr[maxn<<1];int cnt;void addedge(int u,int v,int id){Pr[++cnt].to=v;Pr[cnt].id=id;Pr[cnt].next=E[u];E[u]=&Pr[cnt];Pr[++cnt].to=u;Pr[cnt].id=id;Pr[cnt].next=E[v];E[v]=&Pr[cnt];}int sum[maxn*26],C[maxn*26][27],sz=1;int rt[maxn];char st[maxn][15];void update(int x,int& t,char *st){int len=strlen(st);int y=t=++sz;for(int i=0;i<len;i++){for(int j=0;j<26;j++)C[y][j]=C[x][j];y=C[y][st[i]-'a']=++sz;x=C[x][st[i]-'a'];sum[y]=sum[x]+1;}}int L[maxn],F[maxn][18];int LCA(int u,int v){if(L[u]>L[v])swap(u,v);for(int j=17;j>=0;j--)if(L[F[v][j]]>=L[u])v=F[v][j];if(u==v)return u;for(int j=17;j>=0;j--)if(F[u][j]!=F[v][j])u=F[u][j],v=F[v][j];return F[u][0];}void update(int i){for(int j=1;j<18;j++)F[i][j]=F[F[i][j-1]][j-1];}void Bfs(){static queue<int> Q;Q.push(1);memset(L,0,sizeof(L));L[1]=1;while(!Q.empty()){int u=Q.front();Q.pop();update(u);for(Edge *P=E[u];P;P=P->next)if(!L[P->to]){L[P->to]=L[u]+1;F[P->to][0]=u;update(rt[u],rt[P->to],st[P->id]);Q.push(P->to);}}}int n;void Init(){scanf("%d",&n);for(int i=1;i<n;i++){int u,v;scanf("%d%d%s",&u,&v,st[i]);addedge(u,v,i);}Bfs();}int query(int x,int y,int p,char* st){int len=strlen(st);for(int i=0;i<len;i++)x=C[x][st[i]-'a'],y=C[y][st[i]-'a'],p=C[p][st[i]-'a'];return sum[x]+sum[y]-2*sum[p];}int Q;void Work(){scanf("%d",&Q);for(int i=1;i<=Q;i++){int u,v,p;scanf("%d%d%s",&u,&v,st[0]);p=LCA(u,v);printf("%d\n",query(rt[u],rt[v],rt[p],st[0]));}}int main(){freopen("strings.in","r",stdin);freopen("strings.out","w",stdout);Init();Work();return 0;}


0 1
原创粉丝点击