• AtcoderExaWizards 2019题解


    传送门

    (A Regular Triangle)

    咕咕

    (B Red or Blue)

    咕咕咕

    (C Snuke the Wizard)

    我可能脑子真的坏掉了……

    容易发现不管怎么移动相对顺序都是不变的,那么我们二分找到最右边的会从左边掉出去的点,它左边所有点也会从左边掉出去,最左边的会从右边掉出去的点同理

    //minamoto
    #include<bits/stdc++.h>
    #define R register
    #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    using namespace std;
    char buf[1<<21],*p1=buf,*p2=buf;
    inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    int read(){
        R int res,f=1;R char ch;
        while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
        for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
        return res*f;
    }
    int read(char *s){
    	R int len=0;R char ch;while(((ch=getc())>'Z'||ch<'A'));
    	for(s[++len]=ch;(ch=getc())>='A'&&ch<='Z';s[++len]=ch);
    	return s[len+1]='',len;
    }
    inline char getop(){R char ch;while((ch=getc())>'Z'||ch<'A');return ch;}
    const int N=2e5+5;
    struct node{char c,d;}q[N];char s[N];
    int n,m,l,r,mid,ansl,ansr;
    bool ck(int pos){
    	int x=mid;
    	fp(i,1,m)if(s[x]==q[i].c){
    		q[i].d=='L'?--x:++x;
    		if(x<1||x>n)return x==pos;
    	}
    	return false;
    }
    int main(){
    //	freopen("testdata.in","r",stdin);
    	n=read(),m=read(),read(s);
    	fp(i,1,m)q[i].c=getop(),q[i].d=getop();
    	l=1,r=n,ansl=0;
    	while(l<=r){
    		mid=(l+r)>>1;
    		ck(0)?(ansl=mid,l=mid+1):r=mid-1;
    	}
    	l=1,r=n,ansr=n+1;
    	while(l<=r){
    		mid=(l+r)>>1;
    		ck(n+1)?(ansr=mid,r=mid-1):l=mid+1;
    	}
    	printf("%d
    ",ansr-ansl-1);
    	return 0;
    }
    

    (D Modulo Operations)

    冷静下来突然发现……它题目中说的(set)莫不是就是指(c++)意义上的(set)?不会有重复元素?

    如果先对一个小的数取模再对一个大的数取模,那么后面那个大的数显然没有什么卵用,所以有用的肯定是一个递减序列

    一个数有用,当且仅当所有比它小的数都在它后面,我们设它的排名为(i),那么它以及所有比它小的数的排列个数为(i!),它排在最前面的有((i-1)!),所以它有用的概率就是({1over i})

    那么我们先从小到大(sort)一下,然后倒着做

    (p_{i,j})表示满足所有有用的数字为([i,n])的一个子序列,且最后余数为(j)的概率,初值为(p_{n+1,x}=1)

    转移的话,先给柿子

    [f_{i,jmod a_i}+=f_{i+1,j} imes {1over i} ]

    [f_{i,j}+=f_{i+1,j} imes left({1-{1over i}} ight) ]

    上面的柿子的意思就是,如果当前这个数有用,那么就是上面的转移,没用的话就是下面的转移

    那么最后(f_{1,j} imes n!)就是余数为(j)的期望排列个数

    //minamoto
    #include<bits/stdc++.h>
    #define R register
    #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    using namespace std;
    char buf[1<<21],*p1=buf,*p2=buf;
    inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    int read(){
        R int res,f=1;R char ch;
        while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
        for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
        return res*f;
    }
    const int N=205,M=1e5+5,P=1e9+7;
    inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
    inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
    inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
    int ksm(R int x,R int y){
    	R int res=1;
    	for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
    	return res;
    }
    int inv[N],p[N][M],a[N],id[N];
    int n,x,fac,res;
    int main(){
    //	freopen("testdata.in","r",stdin);
    	n=read(),x=read(),fac=1;
    	fp(i,1,n)a[i]=read(),fac=mul(fac,i);
    	sort(a+1,a+1+n);
    	inv[0]=inv[1]=1;fp(i,2,n)inv[i]=mul(P-P/i,inv[P%i]);
    	p[n+1][x]=1;
    	fd(i,n,1)fp(j,0,x)
    		p[i][j%a[i]]=add(p[i][j%a[i]],mul(p[i+1][j],inv[i])),
    		p[i][j]=add(p[i][j],mul(p[i+1][j],P+1-inv[i]));
    	fp(i,1,x-1)res=add(res,mul(p[1][i],i));
    	printf("%d
    ",mul(res,fac));
    	return 0;
    }
    

    (E Black or White)

    完了我连这种题都做不来了……

    我们记(p_i)表示(i)次取完黑巧克力的答案,(q_i)表示(i)次取完白巧克力的答案,那么第(i)次的答案就是

    [{1-p_{i-1}-q_{i-1}over 2}+q_{i-1} ]

    即如果前(i-1)次哪种巧克力都没有取完,概率就要乘上({1over 2}),如果白巧克力已经取完,那么概率就是(1)

    (p_i)(q_i)可以直接递推了

    //minamoto
    #include<bits/stdc++.h>
    #define R register
    #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    using namespace std;
    char sr[1<<21],z[20];int K=-1,Z=0;
    inline void Ot(){fwrite(sr,1,K+1,stdout),K=-1;}
    void print(R int x){
        if(K>1<<20)Ot();if(x<0)sr[++K]='-',x=-x;
        while(z[++Z]=x%10+48,x/=10);
        while(sr[++K]=z[Z],--Z);sr[++K]='
    ';
    }
    const int N=2e5+5,P=1e9+7,inv2=500000004;
    inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
    inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
    inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
    int ksm(R int x,R int y){
    	R int res=1;
    	for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
    	return res;
    }
    int fac[N],ifac[N],bin[N],pw[N],pb[N],b,w;
    inline int C(R int n,R int m){return m>n?0:1ll*fac[n]*ifac[m]%P*ifac[n-m]%P;}
    int main(){
    //	freopen("testdata.in","r",stdin);
    	scanf("%d%d",&b,&w);
    	fac[0]=ifac[0]=1;fp(i,1,b+w)fac[i]=mul(fac[i-1],i);
    	ifac[b+w]=ksm(fac[b+w],P-2);fd(i,b+w-1,1)ifac[i]=mul(ifac[i+1],i+1);
    	bin[0]=1;fp(i,1,b+w)bin[i]=mul(bin[i-1],inv2);
    	fp(i,1,b+w){
    		pw[i]=add(pw[i-1],mul(C(i-1,w-1),bin[i]));
    		pb[i]=add(pb[i-1],mul(C(i-1,b-1),bin[i]));
    		print(add(1ll*(1+P-pw[i-1]+P-pb[i-1])*inv2%P,pw[i-1]));
    	}
    	return Ot(),0;
    }
    

    (F More Realistic Manhattan Distance)

    我们把起点和终点周围所有方向的边各找出来一条,这样最多是一个(6 imes 6)的网格图,直接跑最短路

    代码已经是完全照抄(yyb)巨巨的了

    //minamoto
    #include<bits/stdc++.h>
    #define R register
    #define ll long long
    #define inf 0x3f3f3f3f
    #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
    using namespace std;
    char buf[1<<21],*p1=buf,*p2=buf;
    inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    int read(){
        R int res,f=1;R char ch;
        while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
        for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
        return res*f;
    }
    int read(char *s){
    	R int len=0;R char ch;while(((ch=getc())>'Z'||ch<'A'));
    	for(s[++len]=ch;(ch=getc())>='A'&&ch<='Z';s[++len]=ch);
    	return s[len+1]='',len;
    }
    char sr[1<<21],z[20];int C=-1,Z=0;
    inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
    void print(R int x){
        if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
        while(z[++Z]=x%10+48,x/=10);
        while(sr[++C]=z[Z],--Z);sr[++C]='
    ';
    }
    vector<int>N,S,W,E;
    int Pre(vector<int> &A,int x){
    	if(A.empty())return 1;
    	int l=0,r=A.size()-1,res=0;
    	while(l<=r){
    		int mid=(l+r)>>1;
    		A[mid]<=x?(res=mid,l=mid+1):r=mid-1;
    	}
    	return A[res];
    }
    int suf(vector<int> &A,int x){
    	if(A.empty())return 1;
    	int l=0,r=A.size()-1,res=r;
    	while(l<=r){
    		int mid=(l+r)>>1;
    		A[mid]>=x?(res=mid,r=mid-1):l=mid+1;
    	}
    	return A[res];
    }
    struct eg{int v,nx,w;}e[1005];int head[105],tot;
    inline void add(R int u,R int v,R int w){e[++tot]={v,head[u],w},head[u]=tot;}
    char s[100005],t[100005];int n,m,Q,cnt,id[25][25],dis[205],vis[205];
    struct node{
    	int u,d;
    	node(){}
    	node(R int uu,R int dd):u(uu),d(dd){}
    	inline bool operator <(const node &b)const{return d>b.d;}
    };priority_queue<node>q;
    int spfa(int S,int T){
    	fp(i,1,cnt)dis[i]=inf,vis[i]=0;
    	q.push(node(S,0)),dis[S]=0;
    	while(!q.empty()){
    		int u=q.top().u;q.pop();if(vis[u])continue;vis[u]=1;
    		go(u)if(cmin(dis[v],dis[u]+e[i].w))q.push(node(v,dis[v]));
    	}
    	return dis[T]<inf?dis[T]:-1;
    }
    int main(){
    //	freopen("testdata.in","r",stdin);
    	n=read(),m=read(),Q=read(),read(s),read(t);
    	fp(i,1,n)s[i]=='E'?E.push_back(i):W.push_back(i);
    	fp(i,1,m)t[i]=='S'?S.push_back(i):N.push_back(i);
    	while(Q--){
    		int a=read(),b=read(),c=read(),d=read();
    		vector<int>X,Y;
    		X.push_back(Pre(E,a)),X.push_back(Pre(W,a)),
    		X.push_back(suf(E,a)),X.push_back(suf(W,a)),
    		X.push_back(Pre(E,c)),X.push_back(Pre(W,c)),
    		X.push_back(suf(E,c)),X.push_back(suf(W,c)),
    		Y.push_back(Pre(S,b)),Y.push_back(Pre(N,b)),
    		Y.push_back(suf(S,b)),Y.push_back(suf(N,b)),
    		Y.push_back(Pre(S,d)),Y.push_back(Pre(N,d)),
    		Y.push_back(suf(S,d)),Y.push_back(suf(N,d));
    		sort(X.begin(),X.end()),X.resize(unique(X.begin(),X.end())-X.begin());
    		sort(Y.begin(),Y.end()),Y.resize(unique(Y.begin(),Y.end())-Y.begin());
    		int lx=X.size(),ly=Y.size(),S,T;cnt=0;
    		fp(i,0,lx-1)fp(j,0,ly-1){
    			id[i][j]=++cnt;
    			if(X[i]==a&&Y[j]==b)S=cnt;
    			if(X[i]==c&&Y[j]==d)T=cnt;
    		}
    		fp(i,1,cnt)head[i]=0;tot=0;
    		fp(i,0,lx-1)
    			if(s[X[i]]=='E')fp(j,0,ly-2)add(id[i][j],id[i][j+1],Y[j+1]-Y[j]);
    			else fp(j,1,ly-1)add(id[i][j],id[i][j-1],Y[j]-Y[j-1]);
    		fp(j,0,ly-1)
    			if(t[Y[j]]=='S')fp(i,0,lx-2)add(id[i][j],id[i+1][j],X[i+1]-X[i]);
    			else fp(i,1,lx-1)add(id[i][j],id[i-1][j],X[i]-X[i-1]);
    		print(spfa(S,T));
    	}
    	return Ot(),0;
    }
    
  • 相关阅读:
    数组、链表、Hash的优缺点
    数据库-索引的坏处,事务的级别,分布式事务的原理。
    4G内存的电脑,如何读取8G的日志文件进行分析,汇总数据成报表的面试题
    数据库常用的锁有哪些
    2020年最新 C# .net 面试题,月薪20K+中高级/架构师必看(十)
    ThreadX应用开发笔记之一:移植ThreadX到STM32平台
    net core 方法 返回值 重改?
    使用RestTemplate发送HTTP请求举例
    dedecms织梦手机站上一篇下一篇链接错误的解决方法
    多目标跟踪之数据关联(匈牙利匹配算法和KM算法)
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/10644535.html
Copyright © 2020-2023  润新知