• 纪中培训 8月8日 day3 考试


    描述:

    MWH寒假外出旅游,来到了S国。S国划分为N个省,第i个省有Ti座城市,编号分别为Ci1,Ci2,……CiTi(各省城市编号不会重复)。所有城市间有M条双向的道路连接,从任意一个城市出发,可到达一切城市,每条道路均须收费。
         此时恰逢春运期间,S国交通运输局采取了优惠措施。当一条路的路费在[L..R]区间时,可免去。同时,每个省也有优惠措施,第i个省内的每条道路路费收其Xi%,连接第i个省和第j个省的每条道路路费收其(Xi%+Xj%)/2。
    MWH想从城市s走到城市t,请求出一对L,R,确保:

    1. MWH能免费到达目的地;
    2. L≤R;
    3. L、R均为整数;
    4. L尽可能地大,R在满足L最大的前提下最小。

    输入

    第一行两个整数N,M。
    接下来M行,每行三个整数,u、v、w,表示连接u、v的道路需收费w。
    接下来N行,第i+M+1行有一个整数Ti,后面Ti个整数,分别是Ci1..CiTi(所有城市编号保证按正整数顺序给出1..  Ti)。
    下一行N个整数X1..Xi。
    最后一行,两个整数,s、t。

    输出

    一行两个整数,如题,L和R。

    样例  

    输入                   输出

    3 7                           2 6
    1 2 3
    5 2 8
    1 3 7
    5 4 5
    2 4 9
    3 5 10
    3 4 2
    2 1 2
    1 3
    2 4 5
    30 50 60
    1 5

    n<=5000  m<=100000 城市<=50000

    注意:因每条道路由各省的交通运输局直接管辖,所以每条道路的路费必须先得到省级优惠,再得到国家级优惠。

    杨神犇提供显然思路,跑一个最大生成树,s->t路径上最小边就是l,然后跑一个最小生成树,强行使刚才的最小边加入树中,s->t路径上最大边就是r,输出即可。

    我的思路是先二分一个l,权值在l~15000的边保留,看s->t是否在同一联通块,并查集判断即可,r同理。

    我的代码:

    #include <cstdio>
    #include <algorithm>
    #include <ctime>
    
    using namespace std;
    const int N=100005;
    
    int n,m;
    int xx[N],yy[N],block[50005],ss,t;
    int dl,dr=16000,maxx;
    double van[N],zk[50005];
    inline int read() { char k=0;char ls;ls=getchar(); for(;ls<'0'||ls>'9';k=ls,ls=getchar()); int x=0;for(;ls>='0'&&ls<='9';ls=getchar())x=x*10+ls-'0'; if(k=='-')x=0-x;return x; }
    struct bcj
    {
        int fa[50005];
        inline void  be(){for(int i=1;i<=maxx;i++)fa[i]=i;}
        int f(int x){return fa[x]=(fa[x]==x)?x:f(fa[x]);}
        int u(int x,int y){fa[f(y)]=f(x);}
    }s;
    
    inline bool gay1(int x)
    {
        s.be();
        for(int i=1;i<=m;++i)
        {
            if(x<=van[i]) s.u(xx[i],yy[i]);
        }
        if(s.f(ss)==s.f(t)) return true;
        return false;
    }
    inline void fuck1()
    {
        int l=0,r=16000,ans;
        while(l<r)
        {
            int mid=(l+r)>>1;
            if(gay1(mid)) l=mid+1,ans=mid;
            else  r=mid;
        }
        dl=ans;
    }
    
    inline bool gay2(int x)
    {
        s.be();
        for(int i=1;i<=m;++i)
        {
            if(dl<=van[i]&&van[i]<=x) s.u(xx[i],yy[i]);
        }
        if(s.f(ss)==s.f(t)) return false;
        return true;
    }
    inline void fuck2()
    {
        int l=0,r=16000,ans;
        while(l<r)
        {
            int mid=(l+r)>>1;//printf("mid=%d
    ",mid);
            if(gay2(mid)) l=mid+1;//,printf("jzsb:l=%d r=%d mid=%d
    ",l,r,mid);
            else r=mid,ans=mid;//,printf("ljjz:l=%d r=%d mid=%d
    ",l,r,mid);
        }
        dr=ans;
    }
    int main()
    {
        freopen("trip.in","r",stdin);
        freopen("trip.out","w",stdout);
    //    double stt=clock();
        n=read();m=read();
        for(int i=1;i<=m;++i){xx[i]=read(),yy[i]=read(),scanf("%lf",&van[i]);maxx=max(max(xx[i],yy[i]),maxx);}
        for(int i=1,T,x;i<=n;++i)
        {
            T=read();
            while(T--) x=read(),block[x]=i;
        }
        
        for(int i=1;i<=n;++i)
        {
            scanf("%lf",&zk[i]);
            zk[i]/=(double)100;
        }
        for(int i=1;i<=m;++i)
        {
            int jzoj=block[xx[i]];
            int laji=block[yy[i]];
            if(jzoj==laji) 
              van[i]*=zk[jzoj];
            else
              van[i]*=(zk[jzoj]+zk[laji])/2;
        }
        /*for(int i=1;i<=m;++i)
        {
            printf("%d %d %lf
    ",xx[i],yy[i],van[i]);
        }*/
        ss=read();t=read();
        fuck1();fuck2();
        printf("%d %d",dl,dr);
    //    double eed=clock();
    //    printf("
    %.2lfms",eed-stt);
    }
    遨游
     
    描述:
    求n全排列字典序第k小是什么?
     
    输入一个n
     

    Data Constraint

    【数据约定】
    对于10%的数据:1<=n<=3
    对于20%的数据,1<=n<=9
    对于30%的数据:1<=n<=18,1<=k<=10^6
    对于60%的数据:1<=n<=18
    对于80%的数据:1<=n<=100,1<=k<=10^100
    对于90%的数据:1<=n<=1000,1<=k<=10^1000
    对于100%的数据:1<=n<=100000,1<=k<=min(10^20000,n!)

    显然过90%数据高精模拟即可。100%数据发现1<=k<=min(10^20000,n!),大概在n>=6000左右开始模拟即可。

    具体先看k的值,来确定第一位放那个:

    如:输入 4 8

    考虑4的全排列第一位放什么,假如第一个放1,后面3个有(n-1)!种放法。

    所以应该放的为k mod (n - i +1)! / (n - i)!    (从大到小枚举i)

    然后 k mod (n - i +1)! / (n - i)!=k div (n - i)! mod (n - i + 1)

    暴力高精除低精,高精取膜,int64 压位即可。(表示没写);

    Description   
      话说, 小X是个数学大佬,他喜欢做数学题。有一天,小X想考一考小Y。他问了小Y一道数学题。题目如下:
          对于一个正整数N,存在一个正整数T(0<T<N),使得

    的值是正整数。
          小X给出N,让小Y给出所有可能的T。如果小Y不回答这个神奇的大佬的简单数学题,他学神的形象就会支离破碎。所以小Y求你帮他回答小X的问题。   (n<=10^14)

    随便推公式即可(感谢van老师教的数学)。

    [n-(t/2)]/(n-t)=k

    1/2+n/[2(n-t)]=k

    1+n/(n-t)=2k

    就是让n/(n-t)为奇数即可,

    枚举n的约数即可。(题解只是提示,细节不多提)

    #include <cstdio>
    #include <algorithm>
    #include <cmath> 
    
    using namespace std;
    
    
    long long n;
    long long a[10000005],b[10000005];
    long long cnt1,cnt2;
    bool flag;
    int main()
    {
        freopen("math.in","r",stdin);
        freopen("math.out","w",stdout);
        scanf("%lld",&n);
        
        if(n==1||n==0||n==2) {printf("0");return 0;}
        int sq=sqrt(n);
        for(long long i=1;i<=sq;++i)
        {
            
            if(n%i==0)
            {
            //    printf("%lld
    ",n%i);
                flag=true;
                long long j=n/i;
            //    printf("%lld %lld
    ",i,j);
                if((j&1)&&i!=n)
                {
                    b[++cnt2]=n-i;
                }
                if((i&1)&&j!=n)
                {
                    a[++cnt1]=n-j;
                }
            }
        }
        if(flag==false)
        {
            printf("1 %lld",n-1);
        }
        else
        {
            printf("%lld ",cnt1+cnt2);
            for(int i=1;i<=cnt1;++i) printf("%lld ",a[i]);
            for(int i=cnt2;i>=1;--i) printf("%lld ",b[i]);
        }
    }
    van

    Description

    被污染的灰灰草原上有羊和狼。有N只动物围成一圈,每只动物是羊或狼。
    该游戏从其中的一只动物开始,报出[1,K]区间的整数,若上一只动物报出的数是x,下一只动物可以报[x+1,x+K]区间的整数,游戏按顺时针方向进行。每只动物报的数字都不能超过M。若一只动物报了M这个数,它所在的种族就输了。问以第i只动物为游戏的开始,最后哪种动物会赢?
     
     

    Input

    第一行输入三个正整数N,M,K。
    接下来一行N个正整数,分别表示N只动物的种类,以顺时针的方向给出。0代表羊,1代表狼。
     
     

    Output

    一行输出N个整数,表示若从第i只动物开始,赢的动物的种类。同上,0代表羊,1代表狼。
     
     

    Sample Input

    Input 1
    2 9 2
    0 1
    Input 2
    6 499 5
    1 0 0 1 1 0
    Input 3
    10 100 10
    0 0 0 1 1 1 1 0 1 1
     

    Sample Output

    Output 1
    0 1
    Output 2
    0 1 1 1 1 0
    Output 3
    1 1 1 1 1 1 1 1 1 1
     
     

    Data Constraint

    对于60%的数据,1 ≤ N, M, K ≤ 500。
    对于100%的数据,1 ≤ N, M, K ≤ 5000。 
     
    一道博弈好题,什么sg函数都不用(其实无所谓),显然报m的话就输了。
    发现数据<=5000
    感觉复杂度O(n²)左右,考虑dp
    dp[i][j]表示第i个人报j时是否能赢。
    考虑转移,
    如果i+1是队友,i报了j,那么i+1报(j+1)~(j+k)里任意一个能赢,i报j就能赢。 (dp[i][j]=dp[i][p]?1:0)(j+1<=p<=k)
    如果i+1是敌人,i报了j,那么i+1报(j+1)~(j+k)里任意一个能赢,i报j就稳输。(dp[i][j]=dp[i][p]?0:1)(j+1<=p<=k)
    查dp[i][p]显然是O(N)然后每个i转移O(N),枚举j O(N),N³显然不行,
    其实查dp[i][p]是否有1用一个后缀和维护就行,详情代码:
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    const int N=5005;
    const int INF=0x3f3f3f3f;
    
    int dp[N<<1][N];
    int hzh[N<<1][N];
    int n,m,kk;
    int a[N],b[N];
    int main()
    {
        freopen("vode.in","r",stdin);
        freopen("vode.out","w",stdout);
        scanf("%d%d%d",&n,&m,&kk);
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&a[i]);
        }
        for(int i=n+1;i<=m+n;++i)
        {
            a[i]=a[i-n];
        }
        //memset(dp,INF,sizeof dp);
        for(int i=1;i<=m;++i) dp[i][m]=0;
        
        
        for(int i=n+m-1;i>=1;--i)
        {
            if(a[i]!=a[i+1])
            {
                for(int j=m-1;j>=1;--j)
                {
                    bool flag=false;
                    //for(int k=j+1;k<=j+kk&&k<=m;++k){if(dp[i+1][k]==1) flag=true;}
                    if(hzh[i+1][j+1]-hzh[i+1][min(m,j+kk)+1]>0) flag=true;
                    if(flag==true) dp[i][j]=0;
                    else dp[i][j]=1;
                    hzh[i][j]=hzh[i][j+1]+dp[i][j]; 
                }
            }
            else 
            {
                for(int j=m-1;j>=1;--j)
                {
                    bool flag=false;
                    //for(int k=j+1;k<=j+kk&&k<=m;++k){if(dp[i+1][k]==1) flag=true;}
                    if(hzh[i+1][j+1]-hzh[i+1][min(m,j+kk)+1]>0) flag=true;
                    if(flag) dp[i][j]=1;
                    else dp[i][j]=0;
                    hzh[i][j]=hzh[i][j+1]+dp[i][j]; 
                }
            }
            
        }
        for(int i=1;i<=n;++i)
        {
            bool flag=false;
            for(int j=1;j<=kk;++j) 
            {
                if(dp[i][j]) {printf("%d ",a[i]);flag=true;break;}
            }
            if(!flag) printf("%d ",a[i]^1);
        }
    }
    meepo的代码

    Description

    有一副n*m的地图,有n*m块地,每块是下列四种中的一种:
    墙:用#表示,墙有4个面,分别是前面,后面,左面,右面。
    起点:用C表示,为主角的起点,是一片空地。
    终点:用F表示,为主角的目的地,是一片空地。
    空地:用 . 表示。
    其中除了墙不能穿过,其他地方都能走。
     
    主角有以下3种操作:
    1.移动到相邻的前后左右的地方,花费一个单位时间。
    2.向前后左右其中一个方向发射子弹,子弹沿直线穿过,打在最近的一堵墙的一面,然后墙的这面就会形成一个开口通往秘密通道。同一时间最多只能有两个开口,若出现有3个开口,出现时间最早的开口会立即消失。该操作不用时间。
    3.可以从一个与开口相邻的空地跳进去,进入秘密通道,从另外一个开口正对的空地跳出来。这个过程花费一个单位时间。

    地图四周都是墙,问主角最少用多少时间从C走到F。C和F
    只会出现一次。
     
     

    Input

    第一行输入两个正整数n,m。
    接下来n行,每行m个字符描述地图。
     

    Output

    输出1个整数,表示最短时间完成路途。如果无解输出nemoguce
     
     

    Sample Input

    Input 1
    4 4
    ####
    #.F#
    #C.#
    ####
    Input 2
    6 8
    ########
    #.##..F#
    #C.##..#
    #..#...#
    #.....##
    ########
    Input 3
    4 5
    #####
    #C#.#
    ###F#
    #####
     

    Sample Output

    Output 1
    2
    Output 2
    4
    Output 3
    nemoguce
     

    Data Constraint

    对于50%的数据,4≤ n,m≤ 15。
    对于100%的数据,4≤ n,m≤ 500。
     
    大意:对于每个点可以花费1代价向上下左右移动,也可以穿过传送门花费一代价,你可以把门开在你所处的点四周的墙上,最多存在两个门,开门不花费。
    卍解:
    bfs难写,考虑转换成图,每个点向四周连长度为1的变,向四周墙前一个点连长度为到四周墙最小距离的变,最短路跑就行。
      1 #include <cstdio>
      2 #include <algorithm>
      3 #include <queue>
      4 #include <cstring>
      5 
      6 using namespace std;
      7 const int N=250005;
      8 const int M=5000000;
      9 const int INF=0x3f3f3f3f;
     10 
     11 struct data
     12 {
     13     int v,nxt,val;
     14 }edge[M];
     15 int cnt,alist[N];
     16 inline void add(int u,int v,int val=1){edge[++cnt]=(data){v,alist[u],val},alist[u]=cnt;}
     17 int n,m,st,ed;
     18 int mmp[505][505];
     19 
     20 inline void fuck(int x,int y)
     21 {
     22     int num=(y-1)*m+x;
     23     if(mmp[x][y+1]==1) {add(y*m+x,num);}
     24     if(mmp[x][y-1]==1) {add((y-2)*m+x,num);}
     25     if(mmp[x-1][y]==1) {add(num-1,num);}
     26     if(mmp[x+1][y]==1) {add(num+1,num);}
     27     
     28     int a1,b1,c1,d1,dd=INF;
     29     for(int i=x+1,temp=0;i<=m;++i)
     30     {
     31         temp++;
     32         if(mmp[i][y]==0) {a1=(y-1)*m+i-1,dd=min(temp,dd);break;}
     33     }
     34     
     35     for(int i=x-1,temp=0;i>=1;--i)
     36     {
     37         temp++;
     38         if(mmp[i][y]==0) {b1=(y-1)*m+i+1,dd=min(temp,dd);break;}
     39      }
     40     
     41     for(int i=y+1,temp=0;i<=n;++i)
     42     {
     43         temp++;
     44         if(mmp[x][i]==0) {c1=(i-2)*m+x,dd=min(temp,dd);break;}
     45     }
     46     
     47     for(int i=y-1,temp=0;i>=1;--i)
     48     {
     49         temp++;
     50         if(mmp[x][i]==0) {d1=(i)*m+x,dd=min(temp,dd);break;}
     51     }
     52     add(num,a1,dd);add(num,b1,dd);add(num,c1,dd);add(num,d1,dd);
     53 }
     54 
     55 bool vis[N];
     56 int dis[N];
     57 struct nod
     58 {
     59     int num,val;
     60     friend bool operator <(nod a,nod b){return a.val>b.val;}
     61 };
     62 inline void dj(int x)
     63 {
     64     priority_queue<nod> q;memset(dis,INF,sizeof dis);
     65     nod pack=(nod){x,0};
     66     dis[x]=0;q.push(pack);
     67     while(!q.empty())
     68     {
     69         int now=q.top().num;q.pop();
     70         if(vis[now]) continue;
     71         vis[now]=true;
     72         for(int i=alist[now];i;i=edge[i].nxt) 
     73         {
     74             int v=edge[i].v;
     75             int val=edge[i].val;
     76             if(dis[now]+val<dis[v])
     77             {
     78                 dis[v]=dis[now]+val;
     79                 nod pack=(nod){v,dis[v]};
     80                 q.push(pack);
     81             }
     82         }
     83     }
     84 }
     85 int main()
     86 {
     87     freopen("portal.in","r",stdin);
     88     freopen("portal.out","w",stdout); 
     89     scanf("%d%d",&n,&m);
     90     for(int j=1;j<=n;++j)
     91     {
     92         for(int i=1;i<=m;++i)
     93         {
     94             char c;
     95             scanf(" %c",&c);
     96             if(c=='#') mmp[i][j]=0;
     97             else if(c=='.') mmp[i][j]=1;
     98             else if(c=='C') mmp[i][j]=1,st=(j-1)*m+i;
     99             else if(c=='F') mmp[i][j]=1,ed=(j-1)*m+i;
    100         }
    101     }
    102     for(int i=2;i<m;++i)
    103     {
    104         for(int j=2;j<n;++j)
    105         {
    106             if(mmp[i][j]) fuck(i,j);
    107         }
    108     }
    109     dj(st);
    110     if(dis[ed]!=INF) printf("%d",dis[ed]);
    111     else printf("nemoguce");
    112 }
    meepo的代码

    Description

    有n个城市,标号为1到n,修建道路花费m天,第i天时,若gcd(a,b)=m-i+1,则标号为a的城市和标号为b的城市会建好一条直接相连的道路,有多次询问,每次询问某两座城市最早什么时候能连通。
     
     

    Input

    第一行输入三个正整数n,m,q,其中q表示询问个数。
    接下来q行,每行两个正整数x,y,表示询问城市x和城市y最早什么时候连通。
     

    Output

    输出q行,每行一个正整数,表示最早连通的天数
     
     

    Sample Input

    Input 1
    8 3 3
    2 5
    3 6
    4 8
    Input 2
    25 6 1
    20 9
    Input 3
    9999 2222 2
    1025 2405
    3154 8949
     

    Sample Output

    Output 1
    3
    1
    2
    Output 2
    4
    Output 3
    1980
    2160
     
     

    Data Constraint

    对于40%的数据,n≤ 1000,q<=100000
    对于100%的数据,1 ≤ n,q≤ 100000,1<=m<=q
     

    大意:挺好理解的;

    卍解:

    对于m-i+1的倍数的点会在第i天连边,

  • 相关阅读:
    ubuntu18.04下eclipse修改maven源为阿里源
    Java中使用队列Queue
    Redis学习笔记——Redis的基本操作
    ubuntu安装redis
    Spring Boot使用监听器Listener
    Spring Boot中在程序中获得application.properties中的值
    Spring Boot使用过滤器Filter
    基于GTID的主从架构异常处理流程
    goroutine与调度器
    使用synergyc共享键鼠
  • 原文地址:https://www.cnblogs.com/AidenPearce/p/9445894.html
Copyright © 2020-2023  润新知