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

    总结

    三道题拿的都是暴力分,和预估的基本一样

    A. 环

    分析

    因为 (n) 不一定是质数,所以要用 (exgcd) 求逆元

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #define rg register
    const int maxn=1e3+5;
    int t,n,k,l;
    char s[maxn];
    int exgcd(rg int aa,rg int bb,rg int &xx,rg int &yy){
    	if(bb==0){
    		xx=1,yy=0;
    		return aa;
    	}
    	rg int nans=exgcd(bb,aa%bb,xx,yy);
    	rg int tt=xx;
    	xx=yy;
    	yy=tt-aa/bb*yy;
    	return nans;
    }
    int gcd(rg int aa,rg int bb){
    	return bb==0?aa:gcd(bb,aa%bb);
    }
    int getny(rg int now){
    	rg int x,y;
    	exgcd(now,n,x,y);
    	x=(x%n+n)%n;
    	return x;
    }
    inline int mulmod(rg long long now1,rg int now2){
    	return now1*=now2,now1>=n?now1%n:now1;
    }
    int main(){
    	scanf("%d",&t);
    	while(t--){
    		memset(s,0,sizeof(s));
    		scanf("%d%d%d",&n,&k,&l);
    		if(gcd(n,k)!=1){
    			printf("NO
    ");
    			continue;
    		}
    		printf("YES
    ");
    		for(rg int i=0;i<n;i++) s[i]='0';
    		for(rg int i=0;i<k;i++) s[i]='0';
    		for(rg int i=0;i<k;i++) s[mulmod(i,getny(k))]='1';
    		for(rg int i=0;i<l;i++){
    			s[mulmod(i,getny(k))]='0';
    			s[(mulmod(i,getny(k))+1)%n]='1';
    			printf("%s
    ",s);
    		}
    	}
    	return 0;
    }
    

    B.DNA序列

    分析

    对于最优解是按照 (1 sim n) 的顺序连接的数据,我们考虑贪心

    枚举每一个字符串有多长的前缀在最优解中,如果比当前答案更优,就更新答案

    枚举的时候应该倒序枚举,而不应该正序枚举

    比如

    AAA
    B
    

    如果我们正着去贪心,那么对于第一个字符串,我们会选择 (A)

    对于第二个字符串,我们会选择 (B)

    最终的答案就是 (AB)

    显然是不对的

    但是如果倒着去贪心

    对于第一个字符串,我们肯定在前面接得越多越好

    所以会得到正确的答案 (AAAB)

    这样做复杂度是 (n^4) 的,(n) 比较小,可以通过

    接下来的问题就在于没有特殊性质的时候如何排序

    考虑把一个字符串 (s) 分成两个部分

    前半部分是一个最短的前缀 (x),满足 (x^{+infty})

    后半部分是该字符串剩下的部分 (y)

    比如 (AACG)

    我们就可以把它写成 (A^{+infty}+CG) 的形式

    这样写会有一个问题,只包含一个字母的字符串无法处理

    因此要在每一个字符串后面加一个字典序较大的字母,比如 (Z)

    那么 (A) 就可以写成 (A^{+infty} + Z) 的形式

    前半部分肯定要按照字典序从小到大排,后半部分则需要按照字典序从大到小排

    因为在前面的字符都相同的情况下

    肯定要把下一个字典序较小的放在后面

    前缀重复正无穷大不好处理

    可以在前缀 (x) 的后面也加一个字典序较大的字母

    这样排序的时候就能够把我们想要的排在前面

    手模几组样例就明白了

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #define rg register
    const int maxn=55,maxm=1e4+5;
    int n,a[maxn][maxn],ans[maxm],len[maxn],anstp,sta[maxm],tp,sum;
    char s[maxn];
    struct jie{
    	std::string x,z;
    	int id;
    }b[maxn];
    bool cmp(rg jie aa,rg jie bb){
    	if(aa.x==bb.x) return aa.z>bb.z;
    	return aa.x<bb.x;
    }
    void updat(){
    	for(rg int i=1;i<=tp;i++){
    		if(sta[i]>ans[i]) return;
    		else if(sta[i]<ans[i]) break;
    	}
    	for(rg int i=1;i<=tp;i++) ans[i]=sta[i];
    	anstp=tp;
    	for(rg int i=tp+1;i<=sum;i++) ans[i]=0;
    }
    void ad(rg int id,rg int nlen){
    	for(rg int i=tp;i>=1;i--) sta[i+nlen]=sta[i];
    	for(rg int i=1;i<=nlen;i++) sta[i]=a[id][i];
    	tp+=nlen;
    }
    void del(rg int nlen){
    	for(rg int i=1;i<=tp-nlen;i++) sta[i]=sta[i+nlen];
    	for(rg int i=tp-nlen+1;i<=tp;i++) sta[i]=0;
    	tp-=nlen;
    }
    int main(){
    	scanf("%d",&n);
    	std::string tmp1,tmp2,tmp3;
    	for(rg int i=1;i<=n;i++){
    		scanf("%s",s+1);
    		len[i]=strlen(s+1);
    		sum+=len[i];
    		tmp1.clear();
    		for(rg int j=1;j<=len[i];j++){
    			if(s[j]=='A') a[i][j]=1;
    			else if(s[j]=='C') a[i][j]=2;
    			else if(s[j]=='G') a[i][j]=3;
    			else a[i][j]=4;
    			tmp1=tmp1+s[j];
    		}
    		tmp1=tmp1+'Z';
    		b[i].id=i;
    		for(rg int j=1;j<=len[i];j++){
    			tmp2.clear();
    			for(rg int k=1;k<=j;k++) tmp2=tmp2+s[k];
    			tmp3=tmp2;
    			while(tmp3.length()<=tmp1.length()) tmp3=tmp3+tmp3;
    			if(tmp3<=tmp1){
    				tmp1.clear();
    				rg int ncnt=0;
    				for(rg int k=j;k<len[i];k++){
    					if(tmp1[k]!=tmp2[k%j]) break;
    					ncnt++;
    				}
    				for(rg int k=j+ncnt/j*j+1;k<=len[i];k++) tmp1=tmp1+s[k];
    				tmp2=tmp2+'Z',tmp1=tmp1+'Z';
    				b[i].x=tmp2,b[i].z=tmp1;
    				break;
    			}
    		}
    	}
    	std::sort(b+1,b+1+n,cmp);
    	for(rg int i=n;i>=1;i--){
    		tp=0;
    		for(rg int j=1;j<=anstp;j++) sta[++tp]=ans[j];
    		for(rg int j=anstp;j>=1;j--) ans[j+1]=ans[j];
    		anstp++;
    		ans[1]=a[b[i].id][1];
    		for(rg int j=2;j<=len[b[i].id];j++) ad(b[i].id,j),updat(),del(j);
    	}
    	for(rg int i=1;i<=anstp;i++){
    		if(ans[i]==1) printf("A");
    		else if(ans[i]==2) printf("C");
    		else if(ans[i]==3) printf("G");
    		else printf("T");
    	}
    	printf("
    ");
    	return 0;
    }
    

    C.探寻

    分析

    把母矿所在处的价值看作无穷大,那么问题就转化成了最少需要多少花费才可以遍历整棵子树

    对于收益减花费为正的结点,肯定能选就选

    将这些节点按照花费从小到大排序

    对于一个收益减花费为正,一个收益减花费为负的节点,肯定要选收益减花费为正的点

    因为 (set) 中不能有重复的元素,所以对于其它的点,也要随便规定一个优先级

    如果当前我们选择的节点能够直接到达

    那么我们肯定要选上这个点

    否则把它与它的父亲合并

    设当前节点为 (now),它的父亲为 (fa)

    分情况讨论

    (cost[now]>val[fa])

    此时父亲节点的收益不足以到达这个节点,所以要把合并之后节点的花费设为 (cost[fa]+cost[now]-val[fa])

    同时收益也要变为 (val[now])

    (cost[now] leq val[fa])

    收益加上当前节点的贡献,变为 (val[fa]+val[now]-cost[now])

    用并查集维护一下所在的集合就行了

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<set>
    #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=1e6+5;
    int fa[maxn],n,f[maxn];
    int zhao(rg int xx){
    	if(xx==fa[xx]) return xx;
    	return fa[xx]=zhao(fa[xx]);
    }
    struct jie{
    	int id;
    	long long cost,val;
    	jie(){}
    	jie(rg int aa,rg long long bb,rg long long cc){
    		id=aa,cost=bb,val=cc;
    	}
    	friend bool operator <(const jie& A,const jie& B){
    		if((A.val-A.cost)>=0 && (B.val-B.cost)>=0){
    			return A.cost==B.cost?A.id<B.id:A.cost<B.cost;
    		} else {
    			if(A.val-A.cost==B.val-B.cost) return A.id<B.id;
    			return A.val-A.cost>B.val-B.cost;
    		}
    	}
    };
    std::set<jie> s;
    long long ans,cs,val[maxn],cost[maxn];
    int main(){
    	n=read();
    	rg int aa,bb,cc;
    	for(rg int i=2;i<=n;i++){
    		aa=read(),bb=read(),cc=read();
    		aa++;
    		f[i]=aa;
    		if(bb!=-1){
    			cost[i]=cc,val[i]=bb;
    		} else {
    			cost[i]=cc,val[i]=0x3f3f3f3f3f3f3f3f;
    		}
    		s.insert(jie(i,cost[i],val[i]));
    	}
    	for(rg int i=1;i<=n;i++) fa[i]=i;
    	rg jie tmp;
    	rg int now;
    	while(!s.empty()){
    		tmp=*s.begin();
    		s.erase(s.begin());
    		now=zhao(f[tmp.id]);
    		if(now==1){
    			if(tmp.cost<=cs){
    				cs=cs-tmp.cost+tmp.val;
    			} else {
    				ans+=tmp.cost-cs;
    				cs=tmp.val;
    			}
    		} else {
    			s.erase(s.find(jie(now,cost[now],val[now])));
    			if(val[now]<cost[tmp.id]){
    				cost[now]=cost[now]+cost[tmp.id]-val[now];
    				val[now]=val[tmp.id];
    			} else {
    				val[now]+=val[tmp.id]-cost[tmp.id];
    			}
    			s.insert(jie(now,cost[now],val[now]));
    		}
    		fa[zhao(tmp.id)]=zhao(now);
    	}	
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    [重回VB6]简单的QQWeb网游辅助工具开发之旅1、序言,另类的QQ登陆方法
    QQ和360大战我的观点
    不用IE Test ,快速对IE兼容性进行测试
    第八届软件设计大赛完全作品赛前评析与剧透
    屌丝如何分发大文件(大于1G)
    NetDog 酷炫版 0.1测试版发布
    Jquery制作的页码插件
    使用Html5+CSS3摆脱JS做带提示文字的输入框
    在nhibernate中,Load相同ID的实体对象的时候出错的问题!
    fieldset,legend
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/14369472.html
Copyright © 2011-2022 走看看