2019牛客多校第二场 A,B,D,E,F,G,H,J

A-Eddy Walker

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

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

B-Eddy Walker2

题目链接:https://blog.csdn.net/henucm/article/details/99566371

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

D-Kth Minimum Clique

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

题目大意:给出一个n个顶点的无向加权图,求第k个最小加权群。两个不同的顶点相邻时,顶点的子集称之为团()

思路:bitset优化暴力求和。将每个点的相邻点用bitset表示,然后暴力求团。由于求的是第k小,所以我们将最小的求出来,依次加边,维护优先队列,直到第k小的团为止。注意一点,新加入的点必须能和之前的点都联通(子集)。同时为了保证不会重复加点,我们都从最后一个点开始加。

ACcode:

#include
#include
#include
#include
#include
// srand(unsigned)time(NULL));rand();
  
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
  
#define ll long long
#define Pair pair
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;
  
const int MAXN=1e2+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{
    ll SumW;
    bitset G;
    Node(ll _SumW=0,bitset _G=0){
        SumW=_SumW;G=_G;
    }
    friend int operator < (Node a,Node b){
        return a.SumW>b.SumW;
    }
};
bitset MP[MAXN];
int W[MAXN];
int n,k;
 
int main(){
    scanf("%d%d",&n,&k);
    for(int i=0;i Tmp;Tmp.reset();
    priority_queue que;que.push(Node(0,Tmp));//从最小的团开始找
    while(que.size()){
        Node u=que.top();que.pop();--k;
//      printf("k=%d,u=(%lld,%d)\n",k,u.SumW,u.top);
        if(k==0){
            printf("%lld\n",u.SumW);
            return 0;
        }Tmp=u.G;
        int Pos=0;
        for(int i=0;i

E-MAZE

题目链接:https://ac.nowcoder.com/acm/contest/882/E

文少DP+线段树:https://blog.csdn.net/henu_1710252529/article/details/102637240

F-Partition problem

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

题目大意:2n个人,分成红队或白队,每个队n人,使得竞争价值最大化。竞争价值是不同对中没对人的竞争价值之和。(任意两人之间的竞争价值之和)。给出一个邻接矩阵,表示的是i,j之间的竞争价值。

思路:枚举第一队的人,刷新竞争价值之和。二进制每一位表示该位置的人是否在1队。然后更新价值。一个二进制枚举题目,n并不大。

ACCode:

#include
#include
#include
#include
#include
// srand(unsigned)time(NULL));rand();
  
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
  
#define ll long long
#define Pair pair
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;
  
const int MAXN=20+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)

ll KP[MAXN][MAXN];
ll Ans;
int n;

void Solve(ll state,int cnt,int pre,ll Val){
	if(cnt==n/2){
		Ans=max(Ans,Val);
		return ;
	}
	if(n-pre-1+cnt>i)&1) tempval-=KP[nxt][i];
			else tempval+=KP[nxt][i];
		}Solve(state|(1ll<

G-Polygons

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

题目大意:给出n条直线,找出这n条直线,判断能够围成的多边形的数量,输出最大最小值,并输出前q个第qi大小的多边形面积。没有输出Invalid question

思路:我们用图的方法解决这道题。将所有的直线之间两两交点做成无向图。遍历每个点,每次找夹角最小的边,然后回归原点后,即可求出所求面积。

2019牛客多校第二场 A,B,D,E,F,G,H,J_第1张图片如图所示,红点表示的是线线之间的交点,绿线表示双向边。

枚举交点,找到最小回路。走完后删掉这条边(边权置为0)。

ACCode:

#include
#include
#include
#include
#include
// srand((unsigned)time(NULL));rand();
       
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
  
#define ll long long
#define PII pair
#define PLL pair
#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=1e12;
const double PI=acos(-1.0);
const double EPS=1.0e-10;
//unsigned register
// ios::sync_with_stdio(false)
 
/*
最多有n^2个面积
求出交点
对于每条直线求出在这条直线上的交点
相邻的两条之间建立双向有向边
遍历每个点,取相邻的夹角最小的边
返回原点后,这条线即为所求面积。
*/
struct Point{
    int flag;
    double x,y;
    Point(double _x=0,double _y=0,int _flag=1){
        x=_x;y=_y;flag=_flag;
    }
    friend Point operator - (Point a,Point b){
        return Point(a.x-b.x,a.y-b.y);
    }
    friend double operator ^ (Point a,Point b){
        return a.x*b.y-a.y*b.x;
    }
};
struct V{
    Point str,end;
    V(Point _str=Point(0,0),Point _end=Point(0,0)){
        str=_str;end=_end;
    }
    void Input(){
        scanf("%lf%lf%lf%lf",&str.x,&str.y,&end.x,&end.y);
    }
    friend V operator - (V a,V b){
        return V(a.str-b.str,a.end-b.end);
    }
};
struct Node1{
    int v,val,nxt;
    Node1(int _v=0,int _val=1,int _nxt=0){
        v=_v;val=_val;nxt=_nxt;
    }
};
Node1 Edge[MAXN*MAXN<<2];
int Head[MAXN*MAXN],Ecnt;
V Vec[MAXN];
vector Dots;
vector Line[MAXN];
int Stk[MAXN*MAXN<<2],top;
double Ans[MAXN*MAXN<<2];int tot;
int n,m;
 
void Intt(){
    clean(Head,-1);Ecnt=0;
}
void AddEdge(int u,int val,int v){
    Edge[Ecnt]=Node1(v,val,Head[u]);
    Head[u]=Ecnt++;
}
int Sgn(double x){
    if(fabs(x)

H-Second Large Rectangle

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

题目大意:给出一个n*m的01矩阵,找出第二小的全1矩阵。

思路:二维单调栈,枚举每一行,维护一个单增栈,每次记录大小。

ACCode:

#include
#include
#include
#include
#include
// srand(unsigned)time(NULL));rand();
  
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
  
#define ll long long
#define Pair pair
#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 Node{
    int l,r,h,S;
    Node(int _l=0,int _r=0,int _h=0){
		l=_l;r=_r;h=_h;
	}
    void IntS(){
        S=(r-l+1)*h;
    }
};
Node Area[MAXN][MAXN];
Pair Stk[MAXN];int top;
map Vis;
char S[MAXN][MAXN];
int A[MAXN][MAXN];
int Sum[MAXN];
int n,m;


int main(){
    scanf("%d%d",&n,&m);
    for(int i=0;i=1&&Stk[top].first>=Sum[j]) --top;
			Area[i][j].l=Stk[top].second+1;
			Area[i][j].h=Sum[j];
			Stk[++top]=make_pair(Sum[j],j);
		}
		top=0;
		Stk[++top]=make_pair(-1,m+1);
		for(int j=m;j>=1;--j){
			while(top>=1&&Stk[top].first>=Sum[j]) --top;
			Area[i][j].r=Stk[top].second-1;
			Stk[++top]=make_pair(Sum[j],j);
		}
        for(int j=1;j<=m;++j) Area[i][j].IntS();
//        for(int j=1;j<=m;++j) printf("j=%d l=%d r=%d h=%d\n",j,Area[i][j].l,Area[i][j].r,Area[i][j].h);
    }
    int fir=0,sec=0;
    for(int i=1;i<=n;++i){
    	Vis.clear();
        for(int j=1;j<=m;++j){
            Pair temp=make_pair(Area[i][j].l,Area[i][j].h);
            if(Vis[temp]) continue;
            Vis[temp]=1;
            if(Area[i][j].S>fir){
                sec=max(fir,max(Area[i][j].S-Area[i][j].h,Area[i][j].S-(Area[i][j].r-Area[i][j].l+1)));
                fir=Area[i][j].S;
                continue;
            }
            if(Area[i][j].S>sec) sec=Area[i][j].S;
//			printf("l=%d,r=%d,h=%d,S=%d\n",Area[i][j].l,Area[i][j].r,Area[i][j].h,Area[i][j].S);
//			printf("fir=%d,sec=%d\n",fir,sec);
        }
    }printf("%d\n",sec);
}

J-Subarray

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

题目大意:有一个1e9长度的全-1数组,现在里面有不超过1e7个1,求有多少个区间数量,区间内之和>0的。

思路:很迷,感觉好难,需要再研究研究。

ACCode:

#include
#include
#include
#include
#include
// srand((unsigned)time(NULL));rand();
       
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
  
#define ll long long
#define PII pair
#define PLL pair
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;
       
const int MAXN=1e6+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-10;
//unsigned register
// ios::sync_with_stdio(false)
 
/*
使用DP求出每段所在的连续段。
每次查询与上次查询的差距==1
从左到右枚举左端点,统计右边比当前值大的个数
*/
int L[MAXN],R[MAXN],Pre[MAXN],Nxt[MAXN];
int Sum[MAXN*30],Cnt[MAXN*30],Lazy[MAXN*30];
int n;
 
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%d%d",&L[i],&R[i]);
    }
    Nxt[1]=R[1]-L[1]+1;
    for(int i=2;i<=n;++i) Nxt[i]=max(0,Nxt[i-1]-(L[i]-R[i-1]-1))+R[i]-L[i]+1;
    Pre[n]=R[n]-L[n]+1;
    for(int i=n-1;i>=1;--i) Pre[i]=max(0,Pre[i+1]-(L[i+1]-R[i]-1))+R[i]-L[i]+1;
    ll Ans=0;
    for(int i=1,base=1e7,j;i<=n;i=j+1){
//      printf("i=%d\n",i);
        j=i+1;
        //处理出来足够覆盖的区间[i,j]
        while(j<=n&&Pre[j]+Nxt[j-1]>=L[j]-R[j-1]-1) ++j;--j;
        int left=max(0,L[i]-Pre[i]),right=min(1000000000-1,R[j]+Nxt[j]);
        int pos=i,mi=INF32,mx=0;
        Sum[0]=0;
        //处理出来前缀和,并且将之加和,确定前缀和区间
        for(int k=left;k<=right;++k){
//          printf("k=%d ",k);
            if(k>=L[pos]&&k<=R[pos]) Sum[k-left+1]=Sum[k-left]+1;
            else Sum[k-left+1]=Sum[k-left]-1;
            if(k==R[pos]) ++pos;
            mi=min(mi,Sum[k-left+1]+base);
            mx=max(mx,Sum[k-left+1]+base);
            Cnt[Sum[k-left+1]+base]++;
        }//printf("\n");
        //处理出来比前缀和大的数量
        for(int k=mx-1;k>=mi;--k) Cnt[k]+=Cnt[k+1];
        Ans+=Cnt[base+1];
        //遍历前缀和,求取每个位置比该位置大的数量
        //刷新Lazy标记
        for(int k=left;k<=right;++k){
//          printf("k=%d ",k);
            int tmp=Sum[k-left+1]+base;
            Cnt[tmp+1]-=Lazy[tmp+1];
            Lazy[tmp]+=Lazy[tmp+1]+1;
            Lazy[tmp+1]=0;
            Ans+=Cnt[tmp+1];
        }
        //初始化
        for(int k=mi;k<=mx;++k) Cnt[k]=Lazy[k]=0;
    }printf("%lld\n",Ans);
}

 

你可能感兴趣的:(2019牛客多校)