百度之星2017初赛题解(A)

T1:

简单数论,问满足(a0+a1*B+...+an*B^n)=a0+a1+...+an(mod P)的P的个数

即满足P|(B-1)a1+(B^2-1)a2+(B^3-1)a3+...,即P|B-1的P的个数

sqrt(B-1)暴力枚举B-1约数即可

T2:

现在给若干个条件,xi=xj或xi≠xj,要你将它们划分成若干组,满足每个组除去最后一个条件时成立,否则不成立。

拿并查集将所有相等的点缩起来,对于每个连通块,挂一个vector或者set储存与他不相等的连通块编号(即并查集的代表元)

启发式合并,每次将vector小的合并到大的中去,复杂度O(nlognα(n))或O(nlog^2nα(n))(实际不满)

PS:SB出题人认为最后一组到最后一个条件若成立就不输出

#include<bits/stdc++.h>
#include<tr1/unordered_set>
#define maxn 200100
using namespace std;
typedef long long ll;
set<ll>st2[maxn];
typedef set<ll>::iterator sit;
int L,T,cnt[maxn],f[maxn],A[maxn],B[maxn],C[maxn];
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
int main(){
    scanf("%d",&L);
    for(int i=1;i<=200010;++i)f[i]=i;
    for(int i=1;i<=L;++i)
        scanf("%d%d%d",&A[i],&B[i],&C[i]);
    for(int i=1,pos;i<=L;i=pos){
        for(pos=i;pos<=L;pos++){
            if(C[pos]){
                int x=find(A[pos]),y=find(B[pos]);
                if(x==y)continue;
                if(st2[x].find(y)!=st2[x].end()){
                    cnt[++T]=pos-i+1;
                    break;
                }
                if(st2[x].size()>st2[y].size())swap(x,y);
                f[x]=y;
                for(sit it=st2[x].begin();it!=st2[x].end();++it)
                    st2[*it].erase(x),st2[*it].insert(y),st2[y].insert(*it);
                st2[x].clear();
            } else {
                int x=find(A[pos]),y=find(B[pos]);
                if(x==y){
                    cnt[++T]=pos-i+1;
                    break;
                }
                st2[x].insert(y),st2[y].insert(x);
            }
        }
        if(pos<=L)pos++;
        for(int j=i;j<pos;++j)
            st2[A[j]].clear(),st2[B[j]].clear(),f[A[j]]=A[j],f[B[j]]=B[j];
    }
    printf("%d\n",T);
    for(int i=1;i<=T;++i)printf("%d\n",cnt[i]);
}

T3:

这个。。。简单题吧,

首先两条路径求交,交集一定是一条路径,一定是一个的LCA在另一条路径上,否则交集就是空

那么维护一个线段树,每个节点表示这个区间的路径求交求出的路径是什么

然后普通线段树那样做即可

T4:

给你个地图(BALABALA...)注意“*”翻转的可达性是所有格子都要翻转

这题。。。如果状压"*"的状态的话,我猜想有用的状态(即可能成为最优)不会很多

于是拿一个hash表spfa暴力DP一番(可能本质上是真·暴力

然后就过了。。。

#include<bits/stdc++.h>
#define get(x,y) ((x*100)+y)
#define inf 1000000007
using namespace std;
typedef unsigned long long ull;
typedef pair<int,bool> par;
ull h(ull id,ull S){return S*19260817+id;}
unordered_map<ull,par>dp;
queue<pair<int,ull> >q;
char c[100][100];
int T,n,m,cas,id[100][100],dx[4]={0,0,1,-1},dy[4]={1,-1,0,0},flag,edx,edy;
ull pre[100][100];
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		dp.clear();
		int ans=inf,x0=0,x1=0,bg,ed;
		for(int i=1;i<=n;++i){
			scanf("%s",c[i]+1);
			for(int j=1;j<=m;++j)
				if(c[i][j]=='S')bg=get(i,j);
				else if(c[i][j]=='E')edx=i,edy=j;
		}
		x1=0,flag=1;
		for(int i=1;i<=n;++i)
			for(int j=1;j<=m;++j)
				if(c[i][j]=='*')id[i][j]=++x1;
				else id[i][j]=0;
		for(int i=1;i<=n;++i)
			for(int j=1;j<=m;++j){
				pre[i][j]=0;
				for(int k=0;k<4;++k){
					int ni=i+dx[k],nj=j+dy[k];
					if(ni<=0||nj<=0||ni>n||nj>m)continue;
					if(c[ni][nj]=='*')pre[i][j]|=1ull<<id[ni][nj];
				}
			}
		q.push(make_pair(bg,0ull)),dp[h(bg,0)].first=1;
		while(q.size()){
			pair<int,ull> u=q.front();q.pop();
			int x,y,p=dp[h(u.first,u.second)].first;
			ull s;
			dp[h(u.first,u.second)].second=0;
			x=u.first/100,y=u.first%100,s=u.second;
		//	printf("<%d,%d,%llu,%d>\n",x,y,s,p);
			if(p+abs(x-edx)+abs(y-edy)>=ans)continue;
			
		
			for(int i=0;i<4;++i){
				int nx=x+dx[i],ny=y+dy[i];ull _s=s;
				if(nx<=0||ny<=0||nx>n||ny>m)continue;
				if((__builtin_popcount(s&pre[nx][ny])&1)^(c[nx][ny]=='x'))continue;
				if(c[nx][ny]!='.'&&c[nx][ny]!='x'){
					if(c[nx][ny]=='E'&&(s&1)){
						ans=min(ans,p+1);
					} else if(c[nx][ny]=='*'){
						_s^=(1ull<<id[nx][ny]);
					} else if(c[nx][ny]=='K'){
						_s|=1;
					}
				}
				ull S=h(get(nx,ny),_s);
				int& _q=dp[S].first;
				if(!_q||_q>p+1){
					_q=p+1;
					if(_q>=ans)continue;
					if(dp[S].second)continue;
					dp[S].second=1,q.push(make_pair(get(nx,ny),_s));	
				}
			}
		}
		printf("Case #%d:\n%d\n",++cas,ans==inf?-1:ans-1);
	}
}

T5:

不想说了,2-29写成2-30,智商-1

T6:

不想说了,bfs/dfs判一下连通块即可

#include<bits/stdc++.h>
using namespace std;
char c[110][110];
int n,m,vis[110][110],flag;
void dfs(int x,int y,int z){
	if(vis[x][y])return ;
	if(x<=0||y<=0||x>n||y>m){flag=1;return ;}
	if(c[x][y]!=z)return ;
	vis[x][y]=1;
	dfs(x+1,y,z),dfs(x,y+1,z),dfs(x-1,y,z),dfs(x,y-1,z);
}
int main(){
	while(scanf("%d%d",&n,&m)==2){
		for(int i=1;i<=n;++i)
			scanf("%s",c[i]+1);
		for(int i=0;i<=n+5;++i)
			for(int j=0;j<=m+5;++j)
				vis[i][j]=0;
		int x0=0,x1=0,_x0=0;
		for(int i=1;i<=n;++i)
			for(int j=1;j<=m;++j){
				if(!vis[i][j]){
					flag=0,dfs(i,j,c[i][j]);
					if(c[i][j]=='1'){
						x1++;
					} else {
						x0++;
						if(!flag)_x0++;
					}
				}
			}
	//	printf("[%d,%d,%d]",x0,x1,_x0);
		if(_x0==1&&x1==1)printf("0\n");
		else if(_x0==0&&x1==1)printf("1\n");
		else printf("-1\n");
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值