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);
}
}
}
}
}