zoukankan      html  css  js  c++  java
  • 省选测试30

    A. 要换换名字

    分析

    暴力的做法就是二分一个长度 (len)

    每一个字符串向所有长度小于等于 (len) 的子序列连边

    然后用 (dinic) 跑一个二分图最大匹配即可

    如果能匹配到n个就返回 (1)

    否则返回 (0)

    发现如果一个字符串有多于 (n) 个子序列,那么一定能匹配

    所以只需要 (bfs) 找出长度前 (n) 小的子序列即可

    分析

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<map>
    #include<queue>
    #include<string>
    #define rg register
    inline int read(){
    	rg int x=0,fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=2e5+5,maxm=305;
    char ss[maxm][maxm];
    int n,len[maxm],nxt[maxm][maxm][28],cnt,l,r,mids;
    std::map<std::string,int> mp;
    std::string rk[maxn];
    struct jie{
    	int len,id;
    	std::string val;
    	jie(){}
    	jie(rg int aa,rg int bb,std::string cc){
    		len=aa,id=bb,val=cc;
    	}
    };
    std::vector<jie> g[maxm];
    void init(rg int id){
    	std::queue<jie> q;
    	std::string tmp;
    	for(rg int i=0;i<26;i++){
    		rg int now=nxt[id][0][i];
    		tmp='a'+i;
    		if(now){
    			q.push(jie(1,now,tmp));
    		}
    	}
    	rg int ncnt=0;
    	while(!q.empty()){
    		rg int tmp1=q.front().id,tmp2=q.front().len;
    		std::string tmp3=q.front().val;
    		q.pop();
    		if(!mp[tmp3]){
    			mp[tmp3]=++cnt;
    			rk[cnt]=tmp3;
    		}
    		g[id].push_back(jie(tmp2,mp[tmp3],tmp3));
    		ncnt++;
    		if(ncnt>=n) return;
    		for(rg int i=0;i<26;i++){
    			if(nxt[id][tmp1][i]){
    				tmp=tmp3+ss[id][nxt[id][tmp1][i]];
    				q.push(jie(tmp2+1,nxt[id][tmp1][i],tmp));
    			}
    		}
    	}
    }
    int h[maxn],tot=2,mmax,h2[maxn],dep[maxn],q[maxn],head,tail,s,t;
    struct asd{
    	int to,nxt,val;
    }b[maxn];
    void ad(int aa,int bb,int cc){
    	b[tot].to=bb;
    	b[tot].nxt=h[aa];
    	b[tot].val=cc;
    	h[aa]=tot++;
    }
    bool bfs(){
    	for(rg int i=0;i<=mmax;i++){
    		dep[i]=0;
    		h[i]=h2[i];
    	}
    	q[head=tail=1]=s;
    	dep[s]=1;
    	while(head<=tail){
    		rg int now=q[head++];
    		for(rg int i=h[now];i!=-1;i=b[i].nxt){
    			rg int u=b[i].to;
    			if(!dep[u] && b[i].val){
    				dep[u]=dep[now]+1;
    				q[++tail]=u;
    			}
    		}
    	}
    	return dep[t];
    }
    int dfs(int now,int ac1){
    	if(now==t) return ac1;
    	int ac2=0;
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		h[now]=i;
    		rg int u=b[i].to;
    		if(dep[u]==dep[now]+1 && b[i].val){
    			rg int nans=dfs(u,std::min(ac1,b[i].val));
    			ac1-=nans;
    			ac2+=nans;
    			b[i].val-=nans;
    			b[i^1].val+=nans;
    		}
    		if(ac1==0) break;
    	}
    	if(ac2==0) dep[now]=0;
    	return ac2;
    }
    int vis[maxn],tim;
    bool jud(rg int val){
    	memset(h,-1,sizeof(h));
    	tot=2,s=cnt+n+1,t=cnt+n+2;
    	for(rg int i=1;i<=n;i++){
    		ad(s,i+cnt,1),ad(i+cnt,s,0);
    	}
    	tim++;
    	for(rg int i=1;i<=n;i++){
    		for(rg int j=0;j<g[i].size();j++){
    			if(g[i][j].len<=val){
    				rg int now=g[i][j].id;
    				if(vis[now]!=tim) ad(now,t,1),ad(t,now,0);
    				ad(i+cnt,now,1),ad(now,i+cnt,0);
    				vis[now]=tim;
    			}
    		}
    	}
    	mmax=t;
    	for(rg int i=1;i<=mmax;i++) h2[i]=h[i];
    	rg int ans=0;
    	while(bfs()) ans+=dfs(s,1e9);
    	return ans==n;
    }
    int main(){
    	n=read();
    	for(rg int i=1;i<=n;i++) scanf("%s",ss[i]+1);
    	for(rg int i=1;i<=n;i++) len[i]=strlen(ss[i]+1);
    	for(rg int i=1;i<=n;i++){
    		for(rg int j=0;j<=len[i];j++){
    			for(rg int k=j+1;k<=len[i];k++){
    				rg int tmp=ss[i][k]-'a';
    				if(!nxt[i][j][tmp]){
    					nxt[i][j][tmp]=k;
    				}
    			}
    		}
    	}
    	for(rg int i=1;i<=n;i++) init(i);
    	for(rg int i=1;i<=n;i++) r=std::max(r,len[i]);
    	l=1;
    	while(l<=r){
    		mids=(l+r)>>1;
    		if(jud(mids)) r=mids-1;
    		else l=mids+1;
    	}
    	if(!jud(l)) printf("-1
    ");
    	else {
    		printf("%d
    ",l);
    		for(rg int i=1;i<=n;i++){
    			for(rg int j=h[i+cnt];j!=-1;j=b[j].nxt){
    				if(b[j].val==0){
    					std::cout<<rk[b[j].to]<<std::endl;
    					break;
    				}
    			}
    		}
    	}
    	return 0;
    }
    

    B. 动态半平面交

    分析

    貌似强制在线的做法空间复杂度是 (log^2n)的,所以这道题没有强制在线

    首先把一个质数 (p) 拆成 (p,p^2,p^3 cdots p^k),每一个对答案的贡献都是 (p)

    考虑如何去掉重复的贡献

    在序列上的做法是记录一个(pre[x]) 表示 (x) 上一次出现的位置

    当把新的 (x) 加入的时候把 (pre[x]) 的贡献减掉即可

    把这个问题搬到树上,就是把所有的节点按照 (dfn) 序从小到大排序,把相邻两个点之间 (lca) 的贡献去掉

    之所以可以这么做是因为我们查询的是整个子树的贡献,它的 (dfn) 序是连续的

    因为是动态的所以要拿 (set) 维护

    然后把所有询问按照深度从小到大排序,同时把所有的点按照深度从小到大排序依次加入

    维护一棵以 (dfn) 序为下标的线段树

    那么要进行的操作就是单点修改和区间查询

    时间复杂度是 (O(nlog^2n))

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<set>
    #include<vector>
    #define rg register
    inline int read(){
    	rg int x=0,fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=1e5+5,mod=998244353;
    inline int addmod(rg int now1,rg int now2){
    	return now1+=now2,now1>=mod?now1-mod:now1;
    }
    inline int delmod(rg int now1,rg int now2){
    	return now1-=now2,now1<0?now1+mod:now1;
    }
    inline int mulmod(rg long long now1,rg int now2){
    	return now1*=now2,now1>=mod?now1%mod:now1;
    }
    inline int ksm(rg int ds,rg int zs){
    	rg int nans=1;
    	while(zs){
    		if(zs&1) nans=mulmod(nans,ds);
    		ds=mulmod(ds,ds);
    		zs>>=1;
    	}
    	return nans;
    }
    int h[maxn],tot=1,n,q;
    struct asd{
    	int to,nxt;
    }b[maxn<<1];
    void ad(rg int aa,rg int bb){
    	b[tot].to=bb;
    	b[tot].nxt=h[aa];
    	h[aa]=tot++;
    }
    int fa[maxn],siz[maxn],dep[maxn],son[maxn];
    void dfs1(rg int now,rg int lat){
    	fa[now]=lat;
    	dep[now]=dep[lat]+1;
    	siz[now]=1;
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		rg int u=b[i].to;
    		if(u==lat) continue;
    		dfs1(u,now);
    		siz[now]+=siz[u];
    		if(son[now]==0 || siz[u]>siz[son[now]]) son[now]=u;
    	}
    }
    int tp[maxn],rk[maxn],dfn[maxn],dfnc;
    void dfs2(rg int now,rg int top){
    	dfn[now]=++dfnc;
    	tp[now]=top;
    	rk[dfnc]=now;
    	if(son[now]) dfs2(son[now],top);
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		rg int u=b[i].to;
    		if(u==son[now] || u==fa[now]) continue;
    		dfs2(u,u);
    	}
    }
    int getlca(rg int xx,rg int yy){
    	while(tp[xx]!=tp[yy]){
    		if(dep[tp[xx]]<dep[tp[yy]]) std::swap(xx,yy);
    		xx=fa[tp[xx]];
    	}
    	return dep[xx]<dep[yy]?xx:yy;
    }
    struct tree{
    	int l,r,val;
    }tr[maxn<<2];
    void push_up(rg int da){
    	tr[da].val=mulmod(tr[da<<1].val,tr[da<<1|1].val);
    }
    void build(rg int da,rg int l,rg int r){
    	tr[da].l=l,tr[da].r=r,tr[da].val=1;
    	if(l==r) return;
    	rg int mids=(l+r)>>1;
    	build(da<<1,l,mids),build(da<<1|1,mids+1,r);
    }
    void xg(rg int da,rg int wz,rg int val){
    	if(tr[da].l==tr[da].r){
    		tr[da].val=mulmod(tr[da].val,val);
    		return;
    	}
    	rg int mids=(tr[da].l+tr[da].r)>>1;
    	if(wz<=mids) xg(da<<1,wz,val);
    	else xg(da<<1|1,wz,val);
    	push_up(da);
    }
    int cx(rg int da,rg int l,rg int r){
    	if(tr[da].l>=l && tr[da].r<=r) return tr[da].val;
    	rg int mids=(tr[da].l+tr[da].r)>>1,nans=1;
    	if(l<=mids) nans=mulmod(nans,cx(da<<1,l,r));
    	if(r>mids) nans=mulmod(nans,cx(da<<1|1,l,r));
    	return nans;
    }
    int a[maxn],sta[maxn*20],stacnt,id[maxn];
    struct longdie{
    	int val,num;
    	longdie();
    	longdie(rg int aa,rg int bb){
    		val=aa,num=bb;
    	}
    };
    std::vector<longdie> g[maxn];
    void divid(rg int id,rg int val){
    	for(rg int i=2;i*i<=val;i++){
    		if(val%i==0){
    			rg int now=1;
    			while(val%i==0){
    				now*=i,val/=i;
    				g[id].push_back(longdie(i,now));
    				sta[++stacnt]=now;
    			}
    		}
    	}
    	if(val>1){
    		g[id].push_back(longdie(val,val));
    		sta[++stacnt]=val;
    	}
    }
    int ans[maxn];
    struct jie{
    	int maxdep,num,id;
    	jie(){}
    	jie(rg int aa,rg int bb,rg int cc){
    		maxdep=aa,num=bb,id=cc;
    	}
    }c[maxn];
    bool cmp(rg jie aa,rg jie bb){
    	return aa.maxdep<bb.maxdep;
    }
    bool cmp2(rg int aa,rg int bb){
    	return dep[aa]<dep[bb];
    }
    std::set<int> s[maxn*20];
    #define sit std::set<int>::iterator
    void updat(rg int num){
    	rg int aa,bb,cc;
    	rg sit it1,it2,it3;
    	for(rg int i=0;i<g[num].size();i++){
    		aa=g[num][i].val,bb=g[num][i].num;
    		xg(1,dfn[num],aa);
    		s[bb].insert(dfn[num]);
    		if(s[bb].size()!=1){
    			it1=it2=it3=s[bb].lower_bound(dfn[num]);
    			if(it1==s[bb].begin()){
    				++it2;
    				cc=getlca(num,rk[*it2]);
    				xg(1,dfn[cc],ksm(aa,mod-2));
    			} else if(++it3==s[bb].end()){
    				--it2;
    				cc=getlca(num,rk[*it2]);
    				xg(1,dfn[cc],ksm(aa,mod-2));
    			} else {
    				++it2,--it1;
    				cc=getlca(num,rk[*it1]);
    				xg(1,dfn[cc],ksm(aa,mod-2));
    				cc=getlca(num,rk[*it2]);
    				xg(1,dfn[cc],ksm(aa,mod-2));
    				cc=getlca(rk[*it1],rk[*it2]);
    				xg(1,dfn[cc],aa);
    			}
    		}
    	}
    }
    int main(){
    	memset(h,-1,sizeof(h));
    	n=read(),n=read();
    	for(rg int i=1;i<=n;i++) a[i]=read();
    	for(rg int i=1;i<=n;i++) divid(i,a[i]);
    	std::sort(sta+1,sta+1+stacnt);
    	stacnt=std::unique(sta+1,sta+1+stacnt)-sta-1;
    	for(rg int i=1;i<=n;i++){
    		for(rg int j=0;j<g[i].size();j++){
    			g[i][j].num=std::lower_bound(sta+1,sta+1+stacnt,g[i][j].num)-sta;
    		}
    	}
    	rg int aa,bb;
    	for(rg int i=1;i<n;i++){
    		aa=read(),bb=read();
    		ad(aa,bb),ad(bb,aa);
    	}
    	dfs1(1,0),dfs2(1,1);
    	build(1,1,n);
    	for(rg int i=1;i<=n;i++) id[i]=i;
    	std::sort(id+1,id+n+1,cmp2);
    	q=read();
    	for(rg int i=1;i<=q;i++){
    		aa=read(),bb=read();
    		c[i]=jie(std::min(dep[aa]+bb,n),aa,i);
    	}
    	std::sort(c+1,c+q+1,cmp);
    	rg int head=1,now=1;
    	for(rg int nowdep=1;nowdep<=n;nowdep++){
    		while(now<=n && dep[id[now]]==nowdep) updat(id[now++]);
    		while(head<=q && c[head].maxdep==nowdep){
    			ans[c[head].id]=cx(1,dfn[c[head].num],dfn[c[head].num]+siz[c[head].num]-1);
    			head++;
    		}
    	}
    	for(rg int i=1;i<=q;i++) printf("%d
    ",ans[i]);
    	return 0;
    }
    

    C. 获取名额

    分析

    要求的式子就是 (1-prodlimits_{i=l}^r(1-frac{a_i}{x}))

    发现 (prodlimits_{i=l}^r(1-frac{a_i}{x})=exp(sumlimits_{i=l}^rln(1-frac{a_i}{x})))

    对于 (ln(1-x)) 进行泰勒展开可以得到 (-sumlimits_{i=1}^{+infty}frac{x^j}{j})

    但是发现当 (1-x) 过小时(ln) 的绝对值过大,容易丢精

    所以设一个阈值,(1-x) 小于这个值的时候暴力算,否则用泰勒展开的前 (30)

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #define rg register
    inline int read(){
    	rg int x=0,fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=6e5+5;
    int n,q,l,r,wz[maxn][25],lg[maxn];
    double a[maxn],val[maxn][25],mmax,ans,x,pre[maxn][32];
    void solve(rg int l,rg int r){
    	if(l>r) return;
    	if(ans<1e-12) return;
    	rg int k=lg[r-l+1];
    	rg int mids=wz[l][k];
    	if(val[l][k]<val[r-(1<<k)+1][k]) mids=wz[r-(1<<k)+1][k];
    	rg double val=a[mids]/x;
    	if(val>0.4){
    		ans*=(1-val);
    		solve(l,mids-1),solve(mids+1,r);
    	} else {
    		rg double sum=0,tmp=x;
    		for(rg int i=1;i<=30;i++){
    			sum+=(pre[r][i]-pre[l-1][i])/tmp;
    			tmp*=x;
    		}
    		ans*=exp(-sum);
    	}
    }
    int main(){
    	n=read(),q=read();
    	for(rg int i=1;i<=n;i++) a[i]=read(),mmax=std::max(mmax,a[i]);
    	for(rg int i=1;i<=n;i++) a[i]/=mmax;
    	for(rg int i=1;i<=n;i++) wz[i][0]=i,val[i][0]=a[i];
    	for(rg int j=1;j<=20;j++){
    		for(rg int i=1;i+(1<<j)-1<=n;i++){
    			if(val[i][j-1]<val[i+(1<<(j-1))][j-1]) wz[i][j]=wz[i+(1<<(j-1))][j-1];
    			else wz[i][j]=wz[i][j-1];
    			val[i][j]=std::max(val[i][j-1],val[i+(1<<(j-1))][j-1]);
    		}
    	}
    	for(rg int i=1;i<=n;i++){
    		rg double tmp=a[i];
    		for(rg int j=1;j<=30;j++){
    			pre[i][j]=pre[i-1][j]+tmp/j;
    			tmp*=a[i];
    		}
    	}
    	for(rg int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
    	for(rg int i=1;i<=q;i++){
    		l=read(),r=read(),x=read();
    		ans=1,x/=mmax;
    		solve(l,r);
    		printf("%.10f
    ",1.0-ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    ios7.0结合storyborad实现页面跳转的总结
    ios上取得设备唯一标志的解决方案
    【iOS】Objective-C简约而不简单的单例模式
    ios应用启动后的自动版本检测方式
    linux安装常用软件和查询基本信息
    配置本地yum仓库
    RedHat 6.5 上将系统语言修改为中文
    RedHat7.4配置yum网络源
    linux环境中,两个不同网段的机器互通
    redhat 配置eth0网卡
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/14448605.html
Copyright © 2011-2022 走看看