2019牛客多校第四场 A,B,C,D,E,J,K

A-meeting

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

题目大意:n个点的树。k个人分别在点Xk,求出所有人都到一个点的最短花费时间。

思路:将所有多余的树枝都砍掉,两次DFS。剩下的都是有用的。求剩下的这棵树的直径,因为直径上的两端点必定是最长的时间花费,因此两次DFS求出直径后,直接计算直径即可。

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=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)
 
struct Node{
    int v,val,nxt;
    Node(int _v=0,int _val=0,int _nxt=0){
        v=_v;val=_val;nxt=_nxt;
    }
};
Node Edge[MAXN<<2];
int Head[MAXN],Ecnt;
int Deep[MAXN],Val[MAXN],Sum[MAXN],Vis[MAXN];
int res,ans,n,m;
 
void Intt(){
    clean(Head,-1);Ecnt=0;
    clean(Deep,0);clean(Val,0);clean(Sum,0);
}
void AddEdge(int u,int v,int val){
    Edge[Ecnt]=Node(v,val,Head[u]);
    Head[u]=Ecnt++;
}
void DFS(int u,int fa,int dep=0){
    Vis[u]=1;
    Deep[u]=dep;
    Sum[u]=Val[u];
    for(int i=Head[u];i+1;i=Edge[i].nxt){
        int v=Edge[i].v;
        if(v==fa) continue;
        if(Edge[i].val==0) continue;
        DFS(v,u,dep+1);Sum[u]+=Sum[v];
        if(Sum[v]==0){//子节点没有贡献 ,砍掉
            Edge[i].val=0;
        }
    }
}
int main(){
    Intt();
    scanf("%d%d",&n,&m);
    for(int i=1;iDeep[rt]) rt=i;
    }
//  printf("rt=%d\n",rt);
    clean(Sum,0);clean(Deep,0);clean(Vis,0);
    DFS(rt,0);//换根继续砍
    clean(Deep,0);
    DFS(rt,0); //求深度
    int d=0;
    for(int i=1;i<=n;++i) d=max(d,Deep[i]);
//  printf("d=%d\n",d);
    int Ans=d%2?d/2+1:d/2;
    printf("%d\n",Ans);
     
}

B-xor

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

数论队友线性基:https://ac.nowcoder.com/acm/contest/884/B

C-sequence

题目链接:https://ac.nowcoder.com/acm/contest/884/C

题目大意:给出两个序列a,b,找出找出最大的值:1≤l≤r≤n max​{min(al…r​)×sum(bl…r​)}

思路:有点类似上半年南昌邀请网络赛https://blog.csdn.net/qq_40482358/article/details/89422999

枚举最小的a[i],确定a[i]的最小区间范围。找到范围内的最大的前缀和和最小的前缀和即可。

a[i]的最小的范围可以用单调栈来维护,从前到后和从后到前分别维护单增的栈。

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=3e6+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 SegTree{
    ll Max[MAXN<<2],Min[MAXN<<2];
     
    void Build(int l,int r,int rt,ll A[]){
        if(l==r){
            Max[rt]=Min[rt]=A[l];
            return ;
        }
        int mid=(l+r)>>1;
        Build(l,mid,rt<<1,A);Build(mid+1,r,rt<<1|1,A);
        Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
        Min[rt]=min(Min[rt<<1],Min[rt<<1|1]);
    }
    ll QueryMax(int ql,int qr,int l,int r,int rt){
        if(ql<=l&&r<=qr) return Max[rt];
        int mid=(l+r)>>1;
        ll res=-INF64;
        if(ql<=mid) res=max(res,QueryMax(ql,qr,l,mid,rt<<1));
        if(qr>mid) res=max(res,QueryMax(ql,qr,mid+1,r,rt<<1|1));
        return res;
    }
    ll QueryMin(int ql,int qr,int l,int r,int rt){
        if(ql<=l&&r<=qr) return Min[rt];
        int mid=(l+r)>>1;
        ll res=INF64;
        if(ql<=mid) res=min(res,QueryMin(ql,qr,l,mid,rt<<1));
        if(qr>mid) res=min(res,QueryMin(ql,qr,mid+1,r,rt<<1|1));
        return res;
    }
};
SegTree Seg;//,SegMin;
ll A[MAXN],B[MAXN];
ll Min[MAXN][2],SumB[MAXN];
int Stk[MAXN],Index[MAXN],top;
int n;
 
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%lld",&A[i]);
    for(int i=1;i<=n;++i) scanf("%lld",&B[i]);
    top=0;
    for(int i=1;i<=n;++i){
        while(top>0&&A[i]=1;--i){
        while(top>0&&A[i]

D-triples I

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

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

E-triples II

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

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

J-free

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

题目大意:一个图,可以走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=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 v,val,nxt;
    Node(int _v=0,int _val=0,int _nxt=0){
        v=_v;val=_val;nxt=_nxt;
    }
};
Node Edge[MAXN<<2];
int Head[MAXN],Ecnt;
int Vis[MAXN][MAXN],Dis[MAXN][MAXN];
int n,m,S,T,k;
 
void Intt(){
    clean(Head,-1);Ecnt=0;
    clean(Vis,0);clean(Dis,INF32);
}
void AddEdge(int u,int v,int val){
    Edge[Ecnt]=Node(v,val,Head[u]);
    Head[u]=Ecnt++;
}
#define Piii pair
#define M_P(a,b,c) make_pair(a,make_pair(b,c))
void Dijkstra(){
    Dis[S][0]=0;
    priority_queue que;que.push(M_P(0,S,0));
    while(que.size()){
        while(Vis[que.top().second.first][que.top().second.second]&&que.size()>0) que.pop();
        Pair p=que.top().second;
        Vis[p.first][p.second]=1;
        for(int i=Head[p.first];i+1;i=Edge[i].nxt){//同层查找
            int v=Edge[i].v;
            if(Vis[v][p.second]==0&&Dis[v][p.second]>Dis[p.first][p.second]+Edge[i].val){
                Dis[v][p.second]=Dis[p.first][p.second]+Edge[i].val;
                que.push(M_P(-Dis[v][p.second],v,p.second));
            }
            if(p.second+1<=k&&Vis[v][p.second+1]==0&&Dis[v][p.second+1]>Dis[p.first][p.second]){
                Dis[v][p.second+1]=Dis[p.first][p.second];
                que.push(M_P(-Dis[v][p.second+1],v,p.second+1));
            }
        }
    }
}
int main(){
    Intt();
    scanf("%d%d%d%d%d",&n,&m,&S,&T,&k);
    for(int i=1;i<=m;++i){
        int u,v,val;scanf("%d%d%d",&u,&v,&val);
        AddEdge(u,v,val);AddEdge(v,u,val);
    }Dijkstra();
    int Ans=INF32;
    for(int i=0;i<=k;++i){
        Ans=min(Ans,Dis[T][i]);
    }printf("%d\n",Ans);
}

K-number

题目链接:https://ac.nowcoder.com/acm/contest/884/K

题目大意:给出一串数字,判断有多少个字符串是300的倍数。

思路:求出前缀之和%3的余数。求出对应的个数。从后向前遍历字符串,cnt表示连续0的个数。

当出现一个不为0的数时,判断该位前面有多少个相同的数(相同的数表示中间相差的有3的倍数)加上后面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 Pair pair
#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)
 
char S[MAXN];
int Sum[MAXN];
int A[4][MAXN];
 
int main(){
    scanf("%s",S+1);
    int len=strlen(S+1);//printf("len=%d\n",len);
    for(int i=1;i<=len;++i){
        Sum[i]=Sum[i-1]+S[i]-'0';
        Sum[i]%=3;
    }
    A[0][0]++;
    for(int i=1;i<=len;++i){
        for(int j=0;j<=2;++j) A[j][i]=A[j][i-1];
        A[Sum[i]][i]++;
    }
//  for(int i=0;i<=2;++i){
//      for(int j=0;j<=len;++j){
//          printf(" %d",A[i][j]);
//      }printf("\n");
//  }
    ll Ans=0;
    int cnt=0;
    for(int i=len;i>=0;--i){
        if(S[i]=='0') cnt++;
        else{
            if(cnt>=2){//Ans+
                int x=Sum[i];
                int num=A[x][i];
                num-=1;
                Ans+=1ll*(cnt-1)*num;
                Ans+=(1ll+cnt)*cnt/2;
            }
            if(cnt==1) Ans++;
            cnt=0;
        }
//      printf("i=%d Ans=%lld\n",i,Ans);
    }printf("%lld\n",Ans);
}

 

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