2019牛客多校第三场 A,B,D,F,G,H,I,J

A-Graph Games

题目链接:https://ac.nowcoder.com/acm/contest/883/A

题目大意:给出n个点,m条边的无向图,每次有两种操作,1:将第l到第r条边都反转(存在变为消失,消失变为存在) 2:求出x,y相邻的点是否相同。

思路:首先判断x,y点是否相同,可以使用异或判断,将每个点赋值一个ll范围内的无符号数,然后通过异或,判断是否相等就可以在O 1时间内得到两点是否相邻点相同了。

接下来就是修改了。由于反转操作是反转的边的顺序反转的,因此我们可以将边按编号分块,求出每一块对每个点的贡献,然后对于修改一整块的,可以使用标记记录一下,剩下的再用在块内暴力就好了。即遍历修改的边,然后刷新顶点的连边就好了。

ACCode:

#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<time.h>
#include<math.h>
// srand(unsigned)time(NULL));rand();
  
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
  
#define ll long long
#define ull unsigned ll
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;
  
const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)

ull Val[MAXN],Sum[MAXN];
ull Block[510][MAXN];int BlockNum,BlockCnt;
int Lazy[510],L[510],R[510];
int U[MAXN<<1],V[MAXN<<1];
int n,m;

int main(){
	srand((unsigned)time(NULL));
	int T;scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;++i){
			Val[i]=rand()+1;Sum[i]=0;
		}
		for(int i=1;i<=m;++i){
			scanf("%d%d",&U[i],&V[i]);
			Sum[U[i]]^=Val[V[i]];Sum[V[i]]^=Val[U[i]];
		}
		BlockCnt=0;BlockNum=sqrt(m);//对边进行分块 
		for(int i=1;i<=m;i+=BlockNum){//每个块内都有Block个边 
			Lazy[++BlockCnt]=0;
			L[BlockCnt]=i;R[BlockCnt]=min(i+BlockNum-1,m);//确定每一块的边界 
			for(int j=1;j<=n;++j) Block[BlockCnt][j]=0;
			for(int j=L[BlockCnt];j<=R[BlockCnt];++j){
			//确定每一块对不同点的贡献,块内的边对不同点的贡献 
				Block[BlockCnt][U[j]]^=Val[V[j]];
				Block[BlockCnt][V[j]]^=Val[U[j]];
			}
		}
		int q;scanf("%d",&q);
		while(q--){
			int opt;scanf("%d",&opt);
			if(opt==1){
				int l,r;scanf("%d%d",&l,&r);//反转边[l,r] 
				int x1=(l-1)/BlockNum+1,x2=(r-1)/BlockNum+1;//确定覆盖了那些块 
				if(x1<x2){//不再同一块内,将所有中间块打上标记 
					for(int i=x1+1;i<x2;++i) Lazy[i]^=1;
					//暴力两端点块内的点 
					for(int i=l;i<=R[x1];++i){ 
						Sum[U[i]]^=Val[V[i]];Sum[V[i]]^=Val[U[i]];
					}
					for(int i=L[x2];i<=r;++i){
						Sum[U[i]]^=Val[V[i]];Sum[V[i]]^=Val[U[i]];
					}
				}
				else{
					for(int i=l;i<=r;++i){//同一块内直接更新即可 
						Sum[U[i]]^=Val[V[i]];Sum[V[i]]^=Val[U[i]];
					}
				}
			}
			else{//查询 S(a)==S(b)? 
				int a,b;scanf("%d%d",&a,&b);
				ull Vala=Sum[a],Valb=Sum[b];
				for(int i=1;i<=BlockCnt;++i){
					if(Lazy[i]){
						Vala^=Block[i][a];Valb^=Block[i][b];
					}
				}printf("%d",Vala==Valb?1:0);
			}
		}printf("\n");
	} 
}

B-Crazy Binary String

题目链接:https://ac.nowcoder.com/acm/contest/883/B

题目大意:给出一个长度为n的01串,求最长的子串和子序列中0和1的个数相等。

思路:子串是连续的,因此直接前缀和求两个相等的前缀和之间的差值即可。子序列可以是不连续的,因此直接找0,1最小的个数就行了。

ACCode:

struct Node{
    int Sum,id;
    Node(int _Sum=0,int _id=0){
        Sum=_Sum;id=_id;
    }
    friend int operator < (Node a,Node b){
        if(a.Sum==b.Sum) return a.id<b.id;
        return a.Sum<b.Sum;
    }
};
Node A[MAXN];
char S[MAXN];
int n;
 
int main(){
    scanf("%d",&n);
    scanf("%s",&S);
    int Sum=0,z=0,o=0;
    for(int i=1;i<=n;++i){
        if(S[i-1]=='1'){
            Sum+=1;o++;
        }
        else{
            Sum+=-1;z++;
        }
        A[i]=Node(Sum,i);
    }A[0]=Node(0,0);sort(A,A+n+1);
//  for(int i=0;i<=n;++i) printf("Sum=%d id=%d\n",A[i].Sum,A[i].id);
    int Ans=0,Pre=A[0].Sum,Pos=A[0].id;
    for(int i=1;i<=n;++i){
        if(A[i].Sum==Pre) Ans=max(Ans,A[i].id-Pos);
        else{
            Pre=A[i].Sum;Pos=A[i].id;
        }
    }printf("%d %d\n",Ans,min(z,o)*2);
     
}

D-Big Integer

题目链接:https://ac.nowcoder.com/acm/contest/883/D

数论队友欧拉计数:https://ac.nowcoder.com/acm/contest/883/D

F-Planting Trees

题目链接:https://ac.nowcoder.com/acm/contest/883/F

题目大意:在一个n*n的矩阵中,每个点代表高度,找出最大的子矩阵满足每个元素之间的相差不大于m。

思路:枚举上下界。枚举右端点,维护两个最小值单增,最大值单减的栈。找到第一个符合要求的左端点即可。

具体可看代码注释:

ACCode:

#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<time.h>
#include<math.h>
// srand(unsigned)time(NULL));rand();
  
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
  
#define ll long long
#define Pair pair<int,int>
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;
  
const int MAXN=5e2+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)
 
int H[MAXN][MAXN];
int Max[MAXN],Min[MAXN];
Pair StkMin[MAXN],StkMax[MAXN];int topMin,topMax,botMin,botMax;
int n,m;
 
void DeBug(int Up,int Dw){
    printf("Up=%d Dw=%d\n",Up,Dw);
    printf("Max:");for(int i=1;i<=n;++i) printf("%d ",Max[i]);printf("\n");
    printf("Min:");for(int i=1;i<=n;++i) printf("%d ",Min[i]);printf("\n");
}
int main(){
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i){
            for(int j=1;j<=n;++j){
                scanf("%d",&H[i][j]);
            }
        }int Ans=0;
        for(int i=1;i<=n;++i){
            for(int j=i;j<=n;++j){//枚举上下界
                if(j==i){
                    for(int k=1;k<=n;++k){
                        Max[k]=Min[k]=H[i][k];
                    }
                }
                else{
                    for(int k=1;k<=n;++k){
                        Max[k]=max(Max[k],H[j][k]);
                        Min[k]=min(Min[k],H[j][k]);
                    }
                }topMax=topMin=botMin=botMax=0;
                int ql=1;
//              DeBug(i,j);
                for(int qr=1;qr<=n;++qr){//枚举右端点
                    while(topMax>botMax&&StkMax[topMax-1].first<Max[qr]) --topMax;
                    StkMax[topMax++]=make_pair(Max[qr],qr);
                    while(topMin>botMin&&StkMin[topMin-1].first>Min[qr]) --topMin;
                    StkMin[topMin++]=make_pair(Min[qr],qr);
                    //此时,StkMin中包含[ql,qr]中的所有点,第一个最小,最后的最大
                    //StkMax中包含[ql,qr]中所有的点,第一个最大,最后一个最小
                    //最后一个就是该点。找到第一个比这个大,最小的比这个小就好了。
                    while(botMax<topMax&&botMin<topMin&&abs(StkMin[botMin].first-StkMax[botMax].first)>m){
                        ++ql;
                        while(botMax<topMax&&StkMax[botMax].second<ql) ++botMax;
                        while(botMin<topMin&&StkMin[botMin].second<ql) ++botMin;
                    }
                    Ans=max(Ans,(j-i+1)*(qr-ql+1));
//                  printf("ql=%d Ans=%d\n",ql,Ans);
                }
            }
        }printf("%d\n",Ans);
    }
}

G-Removing Stones

题目链接:https://ac.nowcoder.com/acm/contest/883/G

数论队友:https://blog.csdn.net/henucm/article/details/99538721

H-Magic Line

题目链接:https://ac.nowcoder.com/acm/contest/883/H

题目大意:图上有n个点,画出一条线使得该线平分所有的点,并且该线不穿过任何一个点。

思路:将所有点坐标排序,由于点点不会重合,因此取[n/2]点。因此有n/2个点位于该点左侧。

点的距离最小为1,如图所示:红点为中间的两个点,做两个全等三角形,过[n/2]点。由于直线不可过点,因此上面的蓝点向上+1,正好交在1/2处(图画的不标准)再向上偏一点就变成了与上一个点重合的地方了。

ACCode:

#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<time.h>
#include<math.h>
// srand(unsigned)time(NULL));rand();
  
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
  
#define ll long long
#define Pair pair<int,int>
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;
  
const int MAXN=1e3+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)
 
struct Point{
    ll x,y,z;
    Point(ll _x=0,ll _y=0){
        x=_x;y=_y;
    }
    friend int operator < (Point a,Point b){
        if(a.x==b.x) return a.y<b.y;
        return a.x<b.x;
    }
    friend Point operator - (Point a,Point b){
        return Point(a.x-b.x,a.y-b.y);
    }
    friend Point operator + (Point a,Point b){
        return Point(a.x+b.x,a.y+b.y);
    }
    friend ll operator ^ (Point a,Point b){
        return a.x*b.y-a.y*b.x;
    }
};
Point Dots[MAXN];
int n;
 
ll Distance(Point a,Point b){
    return ((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int Cmp(Point a,Point b){
    if(a.x==b.x) return a.y<b.y;
    return a.x<b.x;
}
int main(){
    int T;
    while(~scanf("%d",&T)){
        while(T--){
            int n;scanf("%d",&n);
            for(int i=1;i<=n;++i){
                scanf("%lld%lld",&Dots[i].x,&Dots[i].y);
            }sort(Dots+1,Dots+1+n,Cmp);
            n>>=1;
            Point D=Dots[n];
            Point A=D,B=D;
            A.y+=11000000+1;B.y-=11000000;
            A.x-=1;B.x+=1;
            printf("%lld %lld %lld %lld\n",A.x,A.y,B.x,B.y);
        }
    }
}

I-Median

题目链接:https://ac.nowcoder.com/acm/contest/883/I

文少DP:https://blog.csdn.net/henu_1710252529/article/details/101041920

J-LRU management

题目链接:https://ac.nowcoder.com/acm/contest/883/J

题目大意:有一个可以容纳m个元素的数组,每次询问一个元素,如果数组中存在,放到后面,不存在则添加到最后。如果数组中满了,就删掉第一个元素。输出每次访问的结果。1:访问块,并移动或添加,如果原序列中存在放到最后,输出原来的值,如果不存在,放入并且输出当前值,2:查询数据,不存在输出Invalid,存在的话,如果v=1,输出后面的元素,如果v==-1,输出前面的元素,否者输出该点的元素。

思路:list+map模拟,普通map多了个log,可能会T,换成哈希map(unordered_map)。主要还是读题的问题,题目不好读,读懂就容易点了。

ACCode:

#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<time.h>
#include<math.h>
// srand(unsigned)time(NULL));rand();
 
#include<map>
#include<set>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
#include<unordered_map>

#define ll long long
#define Pair pair<string,int>
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;
 
const int MAXN=1e1+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false);

struct Node{
	string name;int val;
	Node(string _name,int _val){
		name=_name;val=_val;
	}
};

unordered_map<string,list<Node>::iterator > S;
list<Node> A;
//list<Node>::iterator Aiter;
char name[MAXN];

inline int ReadInt(){
    int x=0,flag=1;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-') { flag=-1;ch=getchar(); }
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*flag;
}
inline void ReadName(char *S){
	int i=0;char ch=getchar();
	while(ch>'9'||ch<'0') ch=getchar();
	while(ch>='0'&&ch<='9'){ S[i++]=ch;ch=getchar();}S[i]='\0';
}
int main(){
	int T;T=ReadInt();
	while(T--){
		S.clear();A.clear();
		int q,m;q=ReadInt();m=ReadInt();
		while(q--){
			int opt,val;opt=ReadInt();ReadName(name);val=ReadInt();
			if(opt){//查询 
				if(S.find(name)==S.end()){
					puts("Invalid");continue;
				}
				//存在k 
				auto Aiter=S[name];
				if(val==-1){
					if(Aiter==A.begin()) puts("Invalid");
					else printf("%d\n",(--Aiter)->val);
					continue;
				}
				if(val==1){
					++Aiter;
					if(Aiter==A.end()) puts("Invalid");
					else printf("%d\n",Aiter->val);
					continue;
				}printf("%d\n",Aiter->val);
			}
			else{//插入 
				if(S.find(name)==S.end()){//原序列中没有 
					A.push_back(Node(name,val));S[name]=--A.end();//放入最后,更新map 
					if(A.size()>m){//需要删除前面的 
						S.erase(A.begin()->name);//删除map和list首 
						A.pop_front();
					}printf("%d\n",val);
				}
				else{//原序列中存在 
					auto Aiter=S[name];val=Aiter->val;
					S.erase(name);A.erase(Aiter);//删掉源序列中的两个东西 
					A.push_back(Node(name,val));S[name]=--A.end();//重新放入最后,更新map 
					printf("%d\n",val);
				}
			}
		}
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值