zoukankan      html  css  js  c++  java
  • [CSP-S膜你赛]Day1 2019.11.11(暴力大作战)

    T1

    题意

    给出(a,b)两个数的异或、与、或值,求有序数对((a,b))的种数,如果值为-1则表示不确定,保证三个值不全为-1,无数解输出inf

    解法

    签到题,氵氵氵

    首先有(or-and=xor),如果有两个数则相当于三个数都已知;

    (count(i))表示(i)在二进制下1的个数

    1. 只知道一个数:(and,xor:inf;or:3^{count(or)})

    2. 三个数都知道:将每一位分开算,每当存在((or=1,and=0))时答案乘2

    注意判断无解即可。。。

    Code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int T,AND,OR,XOR;
    
    template<class T>
    void read(T &x)
    {
    	char c;int sign=1;
    	while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    	while((c=getchar())>='0'&&c<='9') x=(x*10+c-48); x*=sign;
    }
    
    int main()
    {
    	freopen("bit.in","r",stdin);
    	freopen("bit.out","w",stdout);
    	read(T);
    	while(T--)
    	{
    		read(AND);read(OR);read(XOR);
    		if(OR==-1&&XOR==-1) puts("inf");
    		else if(AND==-1&&OR==-1) puts("inf");
    		else if(AND==-1&&XOR==-1)//sum of 1
    		{
    			ll sum=1;
    			for(int i=30;i>=0;--i) if(OR>>i&1) sum*=3;
    			cout<<sum<<endl;
    		}
    		else
    		{
    			if(AND==-1) AND=OR-XOR;
    			else if(OR==-1) OR=AND+XOR;
    			else if(XOR==-1) XOR=OR-AND;
    			if(AND<0||OR<0||XOR<0||AND>OR||OR-AND!=XOR) puts("0");
    			else
    			{
    				ll sum=1;
    				for(int i=30;i>=0;--i)
    				{
    					int ab=(AND>>i&1),ob=(OR>>i&1),xb=(XOR>>i&1);
    					if((!ab) && ob && xb) sum*=2;
    					else if(ab && ob && (!xb)) sum*=1;
    					else if((!ab) && (!ob) && (!xb)) sum*=1;
    					else { sum=0; break; }
    				}
    				cout<<sum<<endl;
    			}
    		}
    	}
    	return 0;
    }
    

    T2

    题意

    给一个开始为空的集合,支持与一个给出的新集合求交/并,以及给集合中所有元素加/减1,(sum)新元素(leq 3e6)

    解法

    签到题2,水沝淼

    一开题目,bitset?不会用,只能打暴力

    显然开个桶表示集合,只要保证复杂度只与新元素的个数有关既可保证不超时

    (如果用(set)的话,时间复杂度与集合中元素个数有关,可能会T)

    1. 取并集:对于一个新元素,如果它不存在于桶中,则加入桶,计算贡献,否则不管

    2. 取交集(我的做法):清空原集合所有元素,然后加入交集中的所有元素

    3. 加、减1,用个标记(tmp),一个元素加入集合时先加(tmp),输出答案时减去(tmp),加减1对(tmp)加减即可

    代码跟C++入门题一样。。。

    Code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int T,xx[3000005];
    ll ans,siz,bt,tmp;//cout<<ans-siz*tmp,tmp表示每个数需要减去的数值 
    bool sum[5000005],apr[5000005];
    int st[5000005],top;
    
    template<class T>
    void read(T &x)
    {
    	char c;int sign=1;
    	while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    	while((c=getchar())>='0'&&c<='9') x=(x*10+c-48); x*=sign;
    }
    
    int main()//一个数解码x-temp,编码=x+temp
    {
    	freopen("jihe.in","r",stdin);
    	freopen("jihe.out","w",stdout);	
    	bt=tmp=2000005;
    	ans=siz=0;
    	read(T);
    	while(T--)
    	{
    		int k;read(k);
    		if(k==1)//并 
    		{
    			int m,x; read(m);
    			for(int i=1;i<=m;++i)
    			{
    				read(x);
    				x+=tmp;
    				if(!sum[x])
    				{
    					sum[x]=1;
    					ans+=x;
    					++siz;
    					st[++top]=x;
    				}
    			}
    		}
    		else if(k==2)//交 
    		{
    			int m; read(m);
    			for(int i=1;i<=m;++i)//打标记 
    			{
    				read(xx[i]);
    				xx[i]+=tmp;
    				apr[xx[i]]=1;
    			}
    			for(int i=1;i<=top;++i)
    			{
    				if(!apr[st[i]])//没有出现 
    				{
    					sum[st[i]]=0;
    					ans-=st[i];
    					--siz;
    				}
    			}
    			top=0;
    			for(int i=1;i<=m;++i) if(sum[xx[i]]) st[++top]=xx[i];
    			for(int i=1;i<=m;++i) apr[xx[i]]=0;//置零 
    		}
    		else if(k==3) --tmp;
    		else ++tmp;
    		printf("%lld
    ",ans-siz*tmp);
    	}
    	return 0;
    }
    

    T3

    题意

    一个(n imes m)的网格中有一些不同种类的方块,没有方块的位置都为空格,两个方块可以成对,当且仅当它们种类相同且存在一条只由空格构成的路径连接它们,(n,mleq 1000)

    解法

    最容易想到的方法是枚举方块,再bfs一遍可以走到的位置,(O(n^2m^2))

    好一些的方法是枚举极大的白色连通块,一个白色相邻的白色连通块所连接到的相同种类方块均可以成对;但是是否有正确性?

    这样做显然不对,因为同一对方块可能被计算多次,即同时有多个白色连通块同时连接它们;

    一个方块最多与四个白色连通块相接,所以可以考虑容斥
    枚举一个方块的贡献,答案为“与一个白色相接的答案-两个+三个-四个”(如果两个方块同时与这些白色块相连,那么它们可以算作一对)

    用一个结构体储存连接情况,一个方块最多与四种方块连接,分集合有15种,所以一个方块最多15个结构体,对这些结构体排个序就可以找到完全相同的结构体,它们可以成对,数量为(C(sum,2))

    如果两个同类型格子之间直接连接,可以假装在它们之间加一个很小的白色块,继续套上面的做法就行了

    直接快速排序是(O(4 imes 15 imes nmlog(15nm))),会超时(虽然数据没卡就对了,但实际上全1的网格可以卡掉),需要换成基数排序

    Code(快速排序)

    #include<bits/stdc++.h>
    #define N 1005 
    using namespace std;
    typedef long long ll;
    int n,m,k,a[N][N];
    int dox[4]={0,-1,0,1},doy[4]={-1,0,1,0};
    int co[N][N],mp[N][N][4],ndsum;//白色块 
    ll ans=0;
    struct Node
    {
    	int opt,color,id[5];
    }nd[N*N*16];int cnt;
    
    template<class T>
    void read(T &x)
    {
    	char c;int sign=1;
    	while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    	while((c=getchar())>='0'&&c<='9') x=(x*10+c-48); x*=sign;
    }
    void dfs(int x,int y)//对白色块染色 
    {
    	co[x][y]=ndsum;
    	for(int i=0;i<4;++i)
    	{
    		int dx=dox[i]+x,dy=doy[i]+y;
    		if(dx<1||dy<1||dx>n||dy>m||a[dx][dy]) continue;
    		if(!co[dx][dy]) dfs(dx,dy);
    	}
    }
    
    bool cmp(Node a,Node b)
    {
    	if(a.id[1]!=b.id[1]) return a.id[1]<b.id[1];
    	if(a.id[2]!=b.id[2]) return a.id[2]<b.id[2];
    	if(a.id[3]!=b.id[3]) return a.id[3]<b.id[3];
    	if(a.id[4]!=b.id[4]) return a.id[4]<b.id[4];
    	return a.color<b.color;
    }
    int main()
    {
    	freopen("link.in","r",stdin);
    	freopen("link.out","w",stdout);
    	read(n);read(m);read(k);
    	for(int i=1;i<=n;++i)
    	  for(int j=1;j<=m;++j)
    		read(a[i][j]);
    	for(int i=1;i<=n;++i)
    	  for(int j=1;j<=m;++j)
    	    if(!a[i][j]&&!co[i][j]) 
    		  ++ndsum,dfs(i,j);
    	for(int i=1;i<=n;++i)
    	  for(int j=1;j<=m;++j)
    	    if(a[i][j])
    	    {
    	    	int st[5]={0},top=0;
    	    	for(int k=0;k<4;++k)
    	    	{
    	    		int dx=dox[k]+i,dy=doy[k]+j;
    	    		if(dx<1||dy<1||dx>n||dy>m) continue;
    	    		if(!a[dx][dy]) mp[i][j][k]=co[dx][dy];
    	    		else 
    	    		{
    	    			if(a[dx][dy]!=a[i][j]) continue;
    	    			if(k==2||k==3) mp[i][j][k]=++ndsum;
    	    			else mp[i][j][k]=mp[dx][dy][k+2];
    				} 
    	    		bool ok=1;
    	    		for(int c=1;c<=top;++c) if(st[c]==mp[i][j][k]) ok=0;
    	    		if(ok) st[++top]=mp[i][j][k];
    	    	}
    	    	sort(st+1,st+top+1);
    	    	for(int sta=1;sta<(1<<top);++sta)
    	    	{	
    				nd[++cnt].color=a[i][j];
    	    		for(int c=0;c<top;++c)
    				  if(sta>>c&1) nd[cnt].id[++nd[cnt].opt]=st[c+1];
    	    	}
    	    }
    	sort(nd+1,nd+cnt+1,cmp);
    	ll ccf=0;
    	for(int i=1;i<=cnt;++i)
    	{
    		bool ok=1;
    		for(int j=1;j<=4;++j) if(nd[i].id[j]!=nd[i-1].id[j]) ok=0;
    		if(nd[i].color!=nd[i-1].color) ok=0;
    		if(!ok&&i!=1)
    		{
    			if(nd[i-1].opt&1) ans+=(ccf-1)*ccf/2;
    			else ans-=(ccf-1)*ccf/2;
    			ccf=0;
    		}
    		++ccf;
    	}
    	if(ccf) ans+=(nd[cnt].opt&1 ? 1:-1)*(ccf-1)*ccf/2;
    	cout<<ans<<endl;
    	return 0;
    }
    

    或者也可以特殊处理相邻块同色的情况,即加两个相邻格子的贡献当且仅当没有它们不能通过白色格子相通,见std

    std

    #include<bits/stdc++.h>
    inline 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;
    }
    const int maxn=1010;
    typedef std::pair<int,int>pos;
    #define x first
    #define y second
    int n,m;
    inline bool valid(pos tmp){
    	return tmp.x>=0&&tmp.x<n&&tmp.y>=0&&tmp.y<m;
    }
    inline pos operator+(const pos&a,const pos&b){
    	return pos(a.x+b.x,a.y+b.y);
    }
    inline int to_ind(pos curr){
    	return curr.x*m+curr.y;
    }
    int fa[maxn*maxn];
    inline int find(int x){
    	return(x==fa[x])?(x):(fa[x]=find(fa[x]));
    }
    inline int find(pos tmp){
    	int x=to_ind(tmp);
    	return(x==fa[x])?(x):(fa[x]=find(fa[x]));
    }
    inline void uni(int a,int b){
    	fa[find(a)]=find(b);
    }
    inline void uni(pos a,pos b){
    	fa[find(to_ind(a))]=find(to_ind(b));
    }
    const pos exc[]={{-1,0},{1,0},{0,-1},{0,1}};
    typedef unsigned long long ull;
    std::map<ull,int>ms;
    const ull hashlevel=998244353;
    typedef long long ll;
    int valbase[maxn][maxn];
    #define val(tmp) valbase[tmp.first][tmp.second]
    int main(){
    //	freopen("link.in","r",stdin);
    //	freopen("link.out","w",stdout);
    	n=read();m=read();read();
    	pos curr,target;
    	for(curr.x=0;curr.x<n;curr.x++)
    		for(curr.y=0;curr.y<m;curr.y++)
    			val(curr)=read();
    	for(int i=0;i<n*m;i++)
    		fa[i]=i;
    	for(curr.x=0;curr.x<n;curr.x++)
    		for(curr.y=0;curr.y<m;curr.y++)
    			if(!val(curr))
    				for(int k=0;k<4;k++)
    					if(valid(target=curr+exc[k])&&!val(target))
    						uni(curr,target);
    	ll ans=0;
    	int tmp[4];
    	for(curr.x=0;curr.x<n;curr.x++)
    		for(curr.y=0;curr.y<m;curr.y++)
    			if(val(curr)){
    				int cnt=0;
    				for(int k=0;k<4;k++)
    					if(valid(target=curr+exc[k])&&!val(target))
    						tmp[cnt++]=find(target);
    				std::sort(tmp,tmp+cnt);
    				cnt=std::unique(tmp,tmp+cnt)-tmp;
    				for(int k=1;k<(1<<cnt);k++){
    					int choice=0;
    					ull hash=0;
    					for(int p=0;p<cnt;p++)
    						if((1<<p)&k){
    							++choice;
    							(hash*=hashlevel)+=tmp[p];
    						}
    					(hash*=hashlevel)+=val(curr);
    					int contribution=++ms[hash];
    					ans+=(contribution-1)*((choice&1)?1:-1);
    				}
    			}
    	std::set<int>s;
    	int match=0;
    	pos thi;
    	for(curr.x=0;curr.x<n;curr.x++)
    		for(curr.y=0;curr.y<m;curr.y++)
    			if(val(curr)){
    				s.clear();
    				for(int k=0;k<4;k++)
    					if(valid(target=curr+exc[k])&&!val(target))
    						s.insert(find(target));
    				for(int k=0;k<4;k++)
    					if(valid(target=curr+exc[k])&&val(target)==val(curr)){
    						++match;
    						for(int p=0;p<4;p++)
    							if(valid(thi=target+exc[p])&&!val(thi)&&s.count(find(thi))){
    								--match;
    								break;
    							}
    					}
    			}
    	std::cout<<ans+(match>>1);
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
    
  • 相关阅读:
    拖拽改变元素位置或大小bug修复
    拖拽改变元素位置或大小
    vue使用input上传多张图片,可以预览
    javaScript面向对象编程学习(二)
    移动端适配字体大小
    js的时间戳的转换
    vue-cli3.X中的vue.config.js的配置
    javaScript面向对象编程学习(一)
    Visual Studio code 常用插件集集合。
    js的四个小练习
  • 原文地址:https://www.cnblogs.com/Chtholly/p/11834870.html
Copyright © 2011-2022 走看看