zoukankan      html  css  js  c++  java
  • 2019-11-1

    T1

    这道题,挺明显的,就是有一些细节。

    对于要求1:要求(gcd) % (a==0) (gcd)是所有数共同的(gcd)

    对于要求2:要求(a*a<min(c)),(c)是每一组的马匹数

    然后就可以(o(n))做了

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #define LL long long 
    using namespace std;
    LL read(){
    	LL x=0,f=1;char ch=getchar();
    	while(ch<'0' || ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return x*f; 
    }
    template <typename T>void Write(T cn){
    	if(cn<0){putchar('-');cn=0-cn;}
    	LL wei=0;T cm=0;LL cx=cn%10;cn/=10;
    	while(cn) cm=cm*10+cn%10,cn/=10,wei++;
    	while(wei--) putchar(cm%10+48),cm/=10;
    	putchar(cx+48);
    }
    LL n,gcd,minn,limit,q;
    LL get_gcd(LL x,LL y){
    	if(y==0) return x;
    	return get_gcd(y,x%y);
    }
    int main(){
    	freopen("queue.in","r",stdin);
    	freopen("queue.out","w",stdout);
    	n=read();gcd=read();minn=gcd;
    	for(LL i=2,x;i<=n;i++){
    		x=read();minn=min(minn,x);
    		if(x<gcd) swap(x,gcd); 
    		gcd=get_gcd(x,gcd);
    	}
    	limit=sqrt(minn);
    	if(limit*limit==minn) limit--;
    	q=read();
    	for(LL i=1,a,b;i<=q;i++){
    		a=read();b=read();
    		if(b==1){
    			if(gcd%a==0) printf("Yes
    ");
    			else printf("No
    ");
    		}
    		else{
    			if(a<=limit) printf("Yes
    ");
    			else printf("No
    ");
    		}
    	}
    	return 0;
    }
    

    T2

    这道题我在考场上并不是正解,但是居然卡着时间((1.964s))过了。

    先说一下考场上我的解法吧。

    首先将询问离线,将询问按照(l-r+1)从小到大排序。 对于相同长度的询问显然不用再次处理,且相邻长度不同的询问,只需要修改一些(复杂度(O(n))),十分优秀。 而我在每个询问的处理实在是太烂了,正解是对于每个询问的处理十分优秀。。

    先看我的代码(类似于莫队的思想)

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #define LL long long 
    using namespace std;
    const int maxn=2010;
    int read(){
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0' || ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return x*f; 
    }
    template <typename T>void Write(T cn){
    	if(cn<0){putchar('-');cn=0-cn;}
    	int wei=0;T cm=0;int cx=cn%10;cn/=10;
    	while(cn) cm=cm*10+cn%10,cn/=10,wei++;
    	while(wei--) putchar(cm%10+48),cm/=10;
    	putchar(cx+48);
    }
    struct node{
    	int tong[2010],eng[30],maxx,tag;
    	void clear(){
    		memset(tong,0,sizeof(tong));
    		memset(eng,0,sizeof(eng));
    		maxx=0;tag=0;
    	}
    }yuan[2010];
    struct wow{
    	int l,r,len,id;
    }ques[2010];
    int t,n,q,ans[maxn];
    char shawn[2010];
    inline bool cmpl(wow x,wow y){
    	return x.len<y.len;
    }
    int main(){
    	freopen("element.in","r",stdin);
    	freopen("element.out","w",stdout);
    	t=read();
    	while(t--){
    		n=read();q=read();
    		scanf("%s",shawn+1);
    		memset(ans,0,sizeof(ans));
    		for(int i=1;i<=n;i++) yuan[i].clear();
    		for(int i=1;i<=n;i++){
    			yuan[i].tong[1]=1;
    			yuan[i].eng[shawn[i]-'a']=1;
    			yuan[i].maxx=1;yuan[i].tag=0;
    		}
    		for(int i=1;i<=q;i++)
    			ques[i].l=read(),ques[i].r=read(),ques[i].len=(ques[i].r-ques[i].l+1),ques[i].id=i;	
    		sort(ques+1,ques+1+q,cmpl);
    		int qnow=1,nowlen=1,tag=0;
    		while(1){
    			if(nowlen<ques[qnow].len){
    				for(int i=1;i<=n-nowlen;i++){
    					if(yuan[i].eng[shawn[i+nowlen]-'a']){
    						yuan[i].tong[yuan[i].eng[shawn[i+nowlen]-'a']]--;
    						yuan[i].eng[shawn[i+nowlen]-'a']++;
    						yuan[i].tong[yuan[i].eng[shawn[i+nowlen]-'a']]++;
    						yuan[i].tag=0;
    					}
    					else{
    						yuan[i].maxx++;
    						yuan[i].eng[shawn[i+nowlen]-'a']++;
    						yuan[i].tong[1]++;
    						yuan[i].tag=0;
    					}
    				}
    				nowlen++;
    				continue;	
    			}
    			int ql=ques[qnow].l;
    			if(yuan[ql].tag){
    				for(int i=1;i<=n-nowlen+1;i++){
    					if(yuan[ql].tag==yuan[i].tag){
    						ans[ques[qnow].id]++;
    					}
    				}
    			}
    			else{
    				yuan[ql].tag=++tag;
    				for(int i=1;i<=n-nowlen+1;i++){
    					if(yuan[ql].maxx!=yuan[i].maxx) continue;
    					int elenow=0,flag=0;
    					for(int j=1;j<=2000;j++){
    						if(yuan[ql].tong[j]!=yuan[i].tong[j]) break;
    						if(elenow==yuan[ql].maxx){
    							flag=1;break;
    						}	
    						elenow+=yuan[ql].tong[j];
    					}
    					if(flag){
    						ans[ques[qnow].id]++;
    						yuan[i].tag=yuan[ql].tag;	
    					}	
    				}
    			}
    			if(qnow==q) break;
    			qnow++;
    		}
    		for(int i=1;i<=q;i++) Write(ans[i]),printf("
    ");
    	}
    }
    

    再来讲正解:正解并没有将询问离线。首先我们考虑两个区间相似的条件:出现次数相同的字母种类相同。这启发我们用桶来装。然而对于一个字母,其出现次数可能高达(2000);对于一个桶,其有值的下标最多只有26个,如果对于每一次我们都扫一遍桶,是不是太不划算了呢?(居然打到了(o(n))的常数震撼我妈) 因此我们用一个队列来存储标本桶有值的下标,然后用标本桶去与当前区间的桶进行比较,如果完全相同就说明这两个区间相似,(ans++)

    (这是PMH的代码,十分巧妙,然而标算的常数更小,但是更难想到)

    #include<bits/stdc++.h>
    using namespace std;
    int dep[27],tong2[3000];
    int tong1[3000];
    int re(){
    	int i=0;
    	char c=getchar();
    	while(!isdigit(c)) c=getchar();
    	for(;isdigit(c);c=getchar()) i=(i<<1)+(i<<3)+c-'0';
    	return i;
    }
    char a[2005];
    int num;
    queue<int>q;
    bool cmp(){
    	for(int i=1;i<=num;i++){
    		int x=q.front();
    		q.pop();
    		q.push(x);
    		if(tong2[x]!=tong1[x]) return false;
    	}
    	return true;
    }
    int main(){
    	freopen("element.in","r",stdin);
    	freopen("element.out","w",stdout);
    	int t=re();
    	while(t--){
    		int n=re(),qww=re();
    		scanf("%s",a+1);
    		for(int i=1;i<=qww;i++){
    			while(!q.empty()){
    				int x=q.front();
    				q.pop();
    				tong1[x]=0;
    			}
    			int l=re(),r=re();
    			for(int j=l;j<=r;j++){
    				dep[a[j]-'a']++;
    			}
    			num=0;
    			for(int j=0;j<26;j++){
    				if(tong1[dep[j]]==0){
    					num++;q.push(dep[j]);
    				}
    				tong1[dep[j]]++;
    			}
    			r=r-l+1;memset(dep,0,sizeof(dep));
    			tong2[0]=26;
    			for(int j=1;j<=r;j++){
    				tong2[dep[a[j]-'a']]--;
    				dep[a[j]-'a']++;
    				tong2[dep[a[j]-'a']]++;
    			}
    			
    			int ans=0;
    			if(cmp()) ans++;
    			for(int j=r+1;j<=n;j++){
    				tong2[dep[a[j-r]-'a']]--;
    				dep[a[j-r]-'a']--;
    				tong2[dep[a[j-r]-'a']]++;
    				tong2[dep[a[j]-'a']]--;
    				dep[a[j]-'a']++;
    				tong2[dep[a[j]-'a']]++;	
    				if(cmp()) ans++;			
    			}
    			printf("%d
    ",ans);
    			for(int j=0;j<26;j++){
    				if(dep[j]){
    					tong2[dep[j]]=0;
    					dep[j]=0;
    				}
    			}
    			tong2[0]=0;
    		}
    	}
    	return 0;
    }
    

    这是标程,他是用绝对值的思想来处理的两个桶的比较

    #include<bits/stdc++.h>
    #define N 2010
    #define D 26
    using namespace std;
    bool isabc(char ch){
    	return (ch>='a')&&(ch<='z');
    }
    template<typename T> void Read(T &X){
    	X=0;char C=getchar();
    	for (;!isdigit(C);C=getchar());
    	for (; isdigit(C);C=getchar()) X=(X<<3)+(X<<1)+C-'0';
    }
    int T,len,m,Q;
    int L,R,tot;
    int cnt[D],cnt2[D];
    int q[N][D];
    int g[N],f[N];
    bool vis[N];
    int tmp;
    char ch;
    int s[N];
    int ans;
    void add(int x,int sig){
    	if (f[cnt2[x]]>g[cnt2[x]]) tot--;else tot++;
    	f[cnt2[x]]--;
    	cnt2[x]+=sig;
    	if (f[cnt2[x]]>=g[cnt2[x]]) tot++;else tot--;
    	f[cnt2[x]]++;
    	return;
    }
    int main(){
    	freopen("element.in","r",stdin);
    	freopen("element.out","w",stdout);
    	Read(T);
    	while (T--){
    		Read(m);Read(Q);
    		tmp=0;
    		ch=getchar();
    		for (;!isabc(ch);ch=getchar());
    		for (; isabc(ch);ch=getchar()) s[++tmp]=ch-'a';
    		for (int i=1;i<=m;i++){
    			for (int j=0;j<D;j++) q[i][j]=q[i-1][j];
    			q[i][s[i]]++;
    		}
    		while (Q--){
    			for (int i=0;i<D;i++) cnt[i]=cnt2[i]=0;
    			Read(L);Read(R);
    			len=R-L+1;
    			for (int i=0;i<D;i++){
    				cnt[i]=q[R][i]-q[L-1][i];
    				cnt2[i]=q[len][i];
    				g[cnt[i]]++;
    				f[cnt2[i]]++;
    			}
    			tot=0;
    			for (int i=0;i<D;i++)
    				if (!vis[cnt[i]]){
    					vis[cnt[i]]=true;
    					tot+=g[cnt[i]];
    				}
    			for (int i=0;i<D;i++) vis[cnt[i]]=false;
    			for (int i=0;i<D;i++)
    				if (!vis[cnt2[i]]){
    					vis[cnt2[i]]=true;
    					if (f[cnt2[i]]>g[cnt2[i]]) tot+=f[cnt2[i]]-2*g[cnt2[i]];
    					else tot-=f[cnt2[i]];
    				}
    			for (int i=0;i<D;i++) vis[cnt2[i]]=false;
    			ans=0;
    			if (!tot) ans++;
    			for (int i=len+1;i<=m;i++){
    				add(s[i],1);
    				add(s[i-len],-1);
    				if (!tot) ans++;
    			}
    			printf("%d
    ",ans);
    			for (int i=0;i<D;i++){
    				g[cnt[i]]--;
    				f[cnt2[i]]--;
    			}
    		}
    	}
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

    T3

    这道题暴力可以得(40pts)的,然而我竟然爆零了(剪枝剪错QAQ

    正解的思想,十分毒瘤。因为我的脑回路不毒瘤,所以我并没有想不出来,甚至看了题解也看不懂QAQ

    那么讲一讲另一种满分算法:

    首先分析一下这道题的性质:因为所有的儿子都对父亲有自己权值的贡献,所以子树节点一定大于任意子树内权值,相当于子树节点的终点一定不在子树中。而起点向上走一个就已经满足最大值不是自己的条件了。因此显然起点的终点满足(f_{end}<f{i})并且终点不在子树中。

    而在(dfs)序中,子树的(dfs)序一定在子树节点(in)(out)之间。因此终点所需要满足的条件可以转换为((f_{end}<fi)) && ((in_{end}<in_{i}) || (out_{end}>out_{i})) 这是不是有点像二维偏序问题?

    我们考虑分别对(in,out) 排序,以(f)为树状数组的下标,存储前缀或(类比于前缀和)

    然后就完了QAQ

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #define int long long
    using namespace std;
    const int maxn=5000000;
    int read(){
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0' || ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    int times,n,f[maxn],tree[maxn<<1],root,ans[maxn],maxx;
    int fir[maxn],nxt[maxn<<1],to[maxn<<1],tot;
    struct node{
    	int in,id;
    	#define in1(x) ques1[x].in
    	#define id1(x) ques1[x].id
    	#define in2(x) ques2[x].in
    	#define id2(x) ques2[x].id
    }ques1[maxn],ques2[maxn];
    void add(int x,int y){nxt[++tot]=fir[x];fir[x]=tot;to[tot]=y;}
    void dfs(int x,int fa){
    	in1(x)=++times;
    	for(int i=fir[x];i;i=nxt[i]){
    		int y=to[i];if(y==fa) continue ;
    		dfs(y,x);
    		f[x]+=f[y];
    	}
    	
    	in2(x)=++times;
    }
    inline bool cmpl(node x,node y){
    	return x.in<y.in;
    }
    int query(int x){
    	int ans=0;
    	for(;x;x-=(x&-x)){
    		ans|=tree[x];
    	}
    	return ans;
    }
    void update(int x,int y){
    	for(;x<=maxx;x+=(x&-x))
    		tree[x]|=y;
    }
    int query1(int x){
    	int ans=0;
    	for(;x;x-=(x&-x)){
    		ans|=tree[x];
    	}
    	return ans;
    }
    void update1(int x,int y){
    	for(;x<=maxx;x+=(x&-x))
    		tree[x]|=y;
    }
    inline bool cmpll(node x,node y){
    	return x.in>y.in;
    }
    signed main(){
    //	freopen("forever.in","r",stdin);
    //	freopen("forever.out","w",stdout);
    	n=read();root=read();
    	for(int i=1,x,y;i<=n-1;i++){
    		x=read();y=read();
    		add(x,y);add(y,x);
    	}
    	for(int i=1;i<=n;i++)
    		f[i]=read(),id1(i)=id2(i)=i;
    	dfs(root,0);
    	for(int i=1;i<=n;i++)
    		maxx|=f[i];
    	sort(ques1+1,ques1+1+n,cmpl);
    	sort(ques2+1,ques2+1+n,cmpll);
    	for(int i=1;i<=n;i++){
    		ans[ques1[i].id]|=query(f[ques1[i].id]-1);
    		update(f[ques1[i].id],f[ques1[i].id]);
    	}
    	memset(tree,0,sizeof(tree));
    	for(int i=1;i<=n;i++){
    		ans[ques2[i].id]|=query1(f[ques2[i].id]-1);
    		update1(f[ques2[i].id],f[ques2[i].id]);
    	}
    	for(int i=1;i<=n;i++)
    		printf("%d ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    [转载]微软4月13日发布Silverlight 4
    关于文件流Seek以及Read操作的一点不满
    团队基础生成自动化流程之最佳实践(IV) 重写团队基础默认生成流程
    谁是你的下一行CODE
    团队基础生成自动化流程之最佳实践总论(II) – 程序集版本信息
    微软Visual Studio 2010 第三集:幸福要敏捷
    团队基础生成自动化流程之最佳实践(VI) 系统模块化条件编译
    团队基础生成自动化流程之最佳实践(V) 使用Desktop Build
    VS2010 "内存不足" 错误补丁
    彩虹天堂
  • 原文地址:https://www.cnblogs.com/mendessy/p/11779513.html
Copyright © 2011-2022 走看看