zoukankan      html  css  js  c++  java
  • 【题解】NOIP2017 提高组 简要题解

    【题解】NOIP2017 提高组 简要题解

    小凯的疑惑(数论)

    不讲

    时间复杂度

    大力模拟

    奶酪

    并查集模板题

    宝藏

    最优解一定存在一种构造方法是按照深度一步步生成所有的联通性。

    枚举一个根,随后设(dp(i,j))表示最大深度为(i)且当前联通的集合是(j)的最小答案。预处理(dis(u,j))表示当(j)集合内的点都存在时,(u)到这些点的最短的最短边。

    转移:

    [dp(i,j)=min {dp(i-1,j),dp(i-1,s)+(i-1) imes sum_{uin j-s} dis(u,s)} ]

    你会问这样不能保证连边的时候深度为(i-1)啊,可能更小啊?

    但是这样不会影响最优解。

    //@winlere
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    
    using namespace std;  typedef long long ll;
    inline int qr(){
          register int ret=0,f=0;
          register char c=getchar();
          while(!isdigit(c))f|=c==45,c=getchar();
          while(isdigit(c)) ret=ret*10+c-48,c=getchar();
          return f?-ret:ret;
    }
    
    const int maxn=13;
    const int inf=0x3f3f3f3f;
    int e[maxn][maxn];
    int dp[maxn][1<<maxn];
    int dis[maxn][1<<maxn];
    int n,m,rt;
    int cnt=0;
    
    int main(){
          memset(e,0x3f,sizeof e);
          memset(dp,0x3f,sizeof dp);
          n=qr(); m=qr();
          for(int t=1,t1,t2;t<=m;++t)
    	    t1=qr(),t2=qr(),e[t1][t2]=e[t2][t1]=min(e[t1][t2],qr());
          const int K=(1<<n)-1;
          for(int t=0;t<=K;++t)
    	    for(int g=1;g<=n;++g){
    		  if(t<<1>>g&1) continue;
    		  int f=inf;
    		  for(int k=1;k<=n;++k)
    			if(t<<1>>k&1) f=min(f,e[g][k]);
    		  dis[g][t]=f;
    	    }
          int ans=inf;
          for(int rt=1;rt<=n;++rt){
    	    memset(dp,0x3f,sizeof dp);
    	    dp[1][1<<rt>>1]=0;
    	    for(int t=2;t<=n;++t){
    		  for(int i=1;i<=K;++i){
    			dp[t][i]=dp[t-1][i];
    			for(int l=i;l;--l&=i){
    			      int c=l^i,ret=0;
    			      if(dp[t-1][c]>=dp[t][i])continue;
    			      bool f=0;
    			      for(int g=1;g<=n;++g)
    				    if(l<<1>>g&1){
    					  if(dis[g][c]>=inf){ret=inf; break;}
    					  else ret+=dis[g][c];
    					  if(dp[t-1][c]+(t-1)*ret>=dp[t][i]) {f=1;break;}
    				    }
    			      if(f)continue;
    			      dp[t][i]=min((ll)dp[t][i],dp[t-1][c]+(t-1ll)*ret);
    			}
    		  }
    		  ans=min(ans,dp[t][K]);
    	    }
    	    ans=min(ans,dp[1][K]);
          }
          printf("%d
    ",ans);
          return 0;
    }
    
    

    列队

    不会

    好像会线段树动态开点做法,没写

    写了

    //@winlere
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #define mid ((l+r)>>1)
    using namespace std;  typedef long long ll;
    const int maxn=3e5+5,maxm=6e6+5;
    int n,m,q,rt[maxn],ls[maxm],rs[maxm],seg[maxm],cnt;
    ll id[maxn<<1];
    vector<ll> e[maxn];
    int que(const int&k,const int&l,const int&r,int&pos){
          if(!pos)pos=++cnt,seg[pos]=r-l+1;
          --seg[pos];
          if(l==r)return l;
          int g=ls[pos]?seg[ls[pos]]:mid-l+1;
          return g>=k?que(k,l,mid,ls[pos]):que(k-g,mid+1,r,rs[pos]);
    }
    int main(){
          ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
          cin>>n>>m>>q;
          for(int t=1;t<=n;++t) id[t]=1ll*t*m;
          for(int t=n+1,N=n+q,M=m+q,x,y,ans;q--;cout<<id[t++]<<'
    '){
    	    cin>>x>>y;
    	    if(y==m) id[t]=id[ans=que(x,1,N,rt[0])];
    	    else id[t]=(ans=que(y,1,M,rt[x]))<m?(x-1ll)*m+ans:e[x][ans-m], e[x].push_back(id[que(x,1,N,rt[0])]);
          }
          return 0;
    }
    
    
    
    
  • 相关阅读:
    hdu3457(有向图的dp问题)
    nyoj16矩形嵌套(第一道dp关于dag的题目)
    noj1475(递推题)统计多少个1
    hdu1331(记忆化搜索)
    hdu1142(dj+记忆化搜索)
    hdu1978(记忆化搜索)
    用广搜实现的spfa
    hdu1428(记忆化搜索)
    hdu1078(记忆化搜索)
    poj3261(后缀数组)
  • 原文地址:https://www.cnblogs.com/winlere/p/11663699.html
Copyright © 2011-2022 走看看