zoukankan      html  css  js  c++  java
  • XVI Open Cup named after E.V. Pankratiev. GP of Ukraine

    A. Associated Vertices

    首先求出SCC然后缩点,第一次求出每个点能到的点集,第二次收集这些点集即可,用bitset加速,时间复杂度$O(frac{nm}{64})$。

    #include<cstdio>
    #include<bitset>
    using namespace std;
    const int N=10010;
    int n,m,x,y,i,j,g[N],G[N],v[N*3],V[N*3],nxt[N*3],NXT[N*3],ed;
    int vis[N],q[N],h,t;
    int f[N],size[N],d[N],ans;
    bitset<N>dp[N];
    inline void add(int x,int y){
      v[++ed]=y;nxt[ed]=g[x];g[x]=ed;
      V[++ed]=x;NXT[ed]=G[y];G[y]=ed;
    }
    inline void ADD(int x,int y){
      if(x==y)return;
      V[++ed]=y;NXT[ed]=G[x];G[x]=ed;
      d[y]++;
    }
    void dfs1(int x){
      vis[x]=1;
      for(int i=g[x];i;i=nxt[i])if(!vis[v[i]])dfs1(v[i]);
      q[++t]=x;
    }
    void dfs2(int x,int y){
      vis[x]=0;
      f[x]=y;
      size[y]++;
      for(int i=G[x];i;i=NXT[i])if(vis[V[i]])dfs2(V[i],y);
    }
    int main(){
      scanf("%d%d",&n,&m);
      while(m--){
        scanf("%d%d",&x,&y);
        add(x,y);
      }
      for(i=1;i<=n;i++)if(!vis[i])dfs1(i);
      for(i=n;i;i--)if(vis[q[i]])dfs2(q[i],q[i]);
      for(i=1;i<=n;i++)G[i]=0;
      for(i=1;i<=n;i++)for(j=g[i];j;j=nxt[j])ADD(f[i],f[v[j]]);
      for(h=i=1,t=0;i<=n;i++)if(f[i]==i&&!d[i])q[++t]=i;
      while(h<=t){
        x=q[h++];
        for(i=G[x];i;i=NXT[i])if(!(--d[V[i]]))q[++t]=V[i];
      }
      for(i=1;i<=n;i++)dp[f[i]][i]=1;
      for(i=t;i;i--){
        x=q[i];
        for(j=G[x];j;j=NXT[j])dp[x]|=dp[V[j]];
      }
      for(i=1;i<=t;i++){
        x=q[i];
        ans+=size[x]*dp[x].count();
        for(j=G[x];j;j=NXT[j])dp[V[j]]|=dp[x];
      }
      printf("%d",ans);
    }
    

      

    B. Bishops

    容斥。

    #include<bits/stdc++.h>
    const int N=1000010;
    typedef long long LL;
    const int Maxn=1000020;
    LL a[Maxn*2];
    int ok1[Maxn*2];
    int ok2[Maxn*2];
    int n,m;
    int get1(int x){
    	if(x>n+1){
    		return n-(x-n-1);
    	}
    	return x-1;
    }
    int get2(int x){
    	if(x<0)return n-(-x);
    	return n-x;
    }
    LL  ask(int l,int r){LL ret=a[r];if(l>=2)ret-=a[l-2];return ret;}
    int main(){
    	while(scanf("%d%d",&n,&m)!=EOF){
    		LL ans=0;
    		memset(ok1,0,sizeof ok1);
    		memset(ok2,0,sizeof ok2);
    		memset(a,0,sizeof a);
    		for(int i=0;i<m;i++){
    			int x,y;scanf("%d%d",&x,&y);
    			if(!ok1[x+y]){
    				ans+=get1(x+y);
    				ok1[x+y]=1;
    				a[x+y]=1;
    			}
    			if(!ok2[x-y+n]){
    				ans+=get2(x-y);
    				ok2[x-y+n]=1;
    			}
    			//printf("%lld
    ",ans);
    		}
    		for(int i=2;i<=n+n;i++)a[i]+=a[i-2];
    		for(int i=n;i>=1;i--){
    			if(!ok2[i-1+n])continue;
    			ans-=ask(i+1,2*n-(i-1));
    		}
    		for(int i=2;i<=n;i++){
    			if(!ok2[1-i+n])continue;
    			ans-=ask(i+1,2*n-(i-1));
    		}
    		printf("%lld
    ",1LL*n*n-ans);
    	}
    }
    

      

    C. Cool Numbers

    暴力枚举答案即可。

    #include<cstdio>
    const int N=1000010;
    int i,j,k,cnt,q[N],v[N],is[N],ans;
    int rev(int x){
      int t=0;
      while(x)t=t*10+x%10,x/=10;
      return t;
    }
    int main(){
      for(i=2;i<=1000000;i++)if(!v[i]){
        is[i]=1;
        for(j=i+i;j<=1000000;j+=i)v[j]=1;
      }
      for(i=10;i<=1000000;i++)if(is[i]){
        j=rev(i);
        if(i==j)continue;
        if(is[j]){
          q[++cnt]=i;
          //if(cnt<=30)printf("%d %d
    ",i,j);
        }
      }
      scanf("%d",&k);
      if(k>cnt)ans=-1;else ans=q[k];
      printf("%d",ans);
    }
    

      

    D. Diagram

    判断是否存在$K$个数满足坐标模$frac{N}{K}$的值相同即可。

    #include <bits/stdc++.h>
    using namespace std ;
    
    const int MAXN = 100005 ;
    
    map < int , int > mp ;
    
    int a[MAXN] , n , k , l ;
    
    void solve () {
    	mp.clear () ;
    	for ( int i = 0 ; i < n ; ++ i ) {
    		scanf ( "%d" , &a[i] ) ;
    	}
    	scanf ( "%d" , &l ) ;
    	l /= k ;
    	for ( int i = 0 ; i < n ; ++ i ) {
    		mp[a[i] % l] ++ ;
    		if ( mp[a[i] % l] == k ) {
    			printf ( "1
    " ) ;
    			return ;
    		}
    	}
    	printf ( "0
    " ) ;
    }
    
    int main () {
    	while ( ~scanf ( "%d%d" , &n , &k ) ) solve () ;
    	return 0 ;
    }
    

      

    E. Effective Hiring

    考虑将所有人按能力从小到大排序,能力相同的按$2,3,1$的优先级排序,那么问题等价于在这个序列中选择$K$对左右括号,使得选出来的是个合法括号序列,dp即可,时间复杂度$O(NKsqrt{NK})$。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1000010;
    typedef long long LL;
    const int Maxn=100020;
    const LL Inf=1LL<<60;
    LL dp[2][334][334];
    int n,k;
    int a[Maxn],c[Maxn],w[Maxn],id[Maxn];//2->3,3->2
    bool cmp(int x,int y){
    	if(c[x]!=c[y])return c[x]<c[y];
    	return a[x]>a[y];
    }
    void init(int cs){
    	for(int i=0;i<=k;i++)for(int j=0;j<=k;j++)dp[cs][i][j]=Inf;
    }
    void up(LL &x,LL y){
    	if(x>y)x=y;
    }
    int main(){
    	while(scanf("%d%d",&n,&k)!=EOF){
    		for(int i=1;i<=n;i++){
    			id[i]=i;
    			scanf("%d%d%d",a+i,c+i,w+i);
    			if(a[i]==3)a[i]=2;
    			else if(a[i]==2)a[i]=3;
    		}
    		sort(id+1,id+1+n,cmp);
    		int cs=0;
    		init(cs);dp[cs][0][0]=0;
    		for(int i=1;i<=n;i++,cs^=1){
    			int idx=id[i];
    			//printf("idx=%d
    ",idx);
    			init(cs^1);
    			for(int has=0;has<=k;has++){
    				for(int j=0;j<=k;j++){
    					if(dp[cs][has][j]==Inf)continue;
    					//if(i==2&&has==0&&j==1)printf("val=%lld
    ",dp[cs][has][j]);
    					for(int it=1;it<=3;it+=2){
    						if(a[idx]!=2&&a[idx]!=it)continue;
    						int nhas=has+(it==1?1:0);
    						int nj=j+(it==3?1:-1);
    						if(nhas>k||nj>k||nj<0)continue;
    						
    					//if(i==2&&has==0&&j==1)printf("nhas=%d nj=%d
    ",nhas,nj);
    						up(dp[cs^1][nhas][nj],dp[cs][has][j]+w[idx]);
    					}
    					up(dp[cs^1][has][j],dp[cs][has][j]);
    				}
    			}
    		}
    		printf("%lld
    ",dp[cs][k][0]);
    	}
    }
    

      

    F. First And Last

    高精度打表。

    import java.io.*;
    import java.math.*;
    import java.util.*;
    
    public class Main {
    	static int [][]res=new int[11][11];
    	public static void main(String[] args) {
    		for(int i=0;i<10;i++)for(int j=0;j<10;j++)res[i][j]=-1;
    		BigInteger o=BigInteger.ONE;
    		for(int i=0;i<500;i++){
    			int lst=o.mod(BigInteger.valueOf(10)).intValue();
    			int fst=lst;
    			BigInteger x=o;
    			while(x.compareTo(BigInteger.ZERO)>0){
    				fst=(x.mod(BigInteger.valueOf(10))).intValue();
    				x=x.divide(BigInteger.TEN);
    			}
    			if(res[fst][lst]<0)res[fst][lst]=i;
    			o=o.multiply(BigInteger.valueOf(2));
    		}
    		Scanner cin=new Scanner(System.in);
    		while(cin.hasNext()){
    			int a=cin.nextInt();
    			int b=cin.nextInt();
    			System.out.println(res[a][b]);
    		}
    		cin.close();
    	}
    }
    

      

    G. Game of Solitaire

    $ans=gcd(n,k)$。

    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>P;
    typedef pair<ll,P>PI;
    int n,K,i,j,a[30010][8];ll ans,lim=1e18;
    priority_queue<PI,vector<PI>,greater<PI> >q;
    inline void ext(int o,int x){
      ll t=0;
      for(int i=7;~i;i--){
        if(t>lim/x)return;
        t=t*x+a[o][i];
        if(t>lim)return;
      }
      q.push(PI(t,P(o,x)));
    }
    int gcd(int a,int b){return b?gcd(b,a%b):a;}
    int main(){
      scanf("%d%d",&n,&K);
      printf("%d",gcd(n,K));
    }
    

      

    H. Hero’s Quest

    留坑。

    I. Important Or Not?

    首先将串翻转,并用Hash值对操作串进行去重,求出后缀数组,用线段树套set维护区间内重要的子串集合。

    对于每个询问,在线段树上找到$O(log n)$个set,在里面首先lower_bound出最短的满足条件的串,然后往后选取$k$个,最后nth_element即可。

    时间复杂度$O(nlog^2n+nklog n)$。

    #include <bits/stdc++.h>
    using namespace std ;
    
    typedef pair < int , int > pii ;
    
    #define clr( a , x ) memset ( a , x , sizeof a )
    #define root 1 , 1 , n
    #define ls o << 1
    #define rs o << 1 | 1 
    #define lson ls , l , m
    #define rson rs , m + 1 , r
    
    const int MAXN = 200005 ;
    const int seed = 233 ;
    const int P1 = 1e9 + 7 , P2 = 998244353 ;
    const int LOGF = 20 ;
    
    char s[MAXN] ;
    int sa[MAXN] , rnk[MAXN] , height[MAXN] ;
    int t1[MAXN] , t2[MAXN] , xy[MAXN] , c[MAXN] ;
    int dp[MAXN][LOGF] , logn[MAXN] ;
    set < pii > T[MAXN << 2] ;
    set < pii > :: iterator it ;
    map < pii , int > mp1 ;
    map < pii , int > mp2 ;
    map < pii , int > mp3 ;
    int a[MAXN] , cnt ;
    int p1[MAXN] , p2[MAXN] ;
    int h1[MAXN] , h2[MAXN] ;
    int n , q ;
    
    int cmp ( int* r , int a , int b , int d ) {
    	return r[a] == r[b] && r[a + d] == r[b + d] ;
    }
    
    void get_height ( int n , int k = 0 ) {
    	for ( int i = 0 ; i <= n ; ++ i ) rnk[sa[i]] = i ;
    	for ( int i = 0 ; i < n ; ++ i ) {
    		if ( k ) -- k ;
    		int j = sa[rnk[i] - 1] ;
    		while ( s[i + k] == s[j + k] ) ++ k ;
    		height[rnk[i]] = k ;
    	}
    }
    
    void da ( int n , int m ) {
    	int *x = t1 , *y = t2 ;
    	for ( int i = 0 ; i < m ; ++ i ) c[i] = 0 ;
    	for ( int i = 0 ; i < n ; ++ i ) c[x[i] = s[i]] ++ ;
    	for ( int i = 1 ; i < m ; ++ i ) c[i] += c[i - 1] ;
    	for ( int i = n - 1 ; i >= 0 ; -- i ) sa[-- c[x[i]]] = i ;
    	for ( int d = 1 , p = 0 ; p < n ; d <<= 1 , m = p ) {
    		p = 0 ;
    		for ( int i = n - d ; i < n ; ++ i ) y[p ++] = i ;
    		for ( int i = 0 ; i < n ; ++ i ) if ( sa[i] >= d ) y[p ++] = sa[i] - d ;
    		for ( int i = 0 ; i < m ; ++ i ) c[i] = 0 ;
    		for ( int i = 0 ; i < n ; ++ i ) c[xy[i] = x[y[i]]] ++ ;
    		for ( int i = 1 ; i < m ; ++ i ) c[i] += c[i - 1] ;
    		for ( int i = n - 1 ; i >= 0 ; -- i ) sa[-- c[xy[i]]] = y[i] ;
    		swap ( x , y ) ;
    		p = 0 ;
    		x[sa[0]] = p ++ ;
    		for ( int i = 1 ; i < n ; ++ i ) x[sa[i]] = cmp ( y , sa[i - 1] , sa[i] , d ) ? p - 1 : p ++ ;
    	}
    	get_height ( n - 1 ) ;
    }
    
    int rmq ( int L , int R ) {
    	int k = logn[R - L + 1] ;
    	return min ( dp[L][k] , dp[R - ( 1 << k ) + 1][k] ) ;
    }
    
    void init_rmq ( int n ) {
    	for ( int i = 1 ; i <= n ; ++ i ) dp[i][0] = height[i] ;
    	logn[1] = 0 ;
    	for ( int i = 2 ; i <= n ; ++ i ) logn[i] = logn[i - 1] + ( i == ( i & -i ) ) ;
    	for ( int j = 1 ; ( 1 << j ) < n ; ++ j ) {
    		for ( int i = 1 ; i + ( 1 << j ) - 1 <= n ; ++ i ) {
    			dp[i][j] = min ( dp[i][j - 1] , dp[i + ( 1 << ( j - 1 ) )][j - 1] ) ;
    		}
    	}
    }
    
    int get_L ( int x , int l , int r ) {
    	int R = r ;
    	while ( l < r ) {
    		int m = l + r >> 1 ;
    		if ( rmq ( m + 1 , R ) >= x ) r = m ;
    		else l = m + 1 ;
    	}
    	return l ;
    }
    
    int get_R ( int x , int l , int r ) {
    	int L = l ;
    	while ( l < r ) {
    		int m = l + r + 1 >> 1 ;
    		if ( rmq ( L + 1 , m ) >= x ) l = m ;
    		else r = m - 1 ;
    	}
    	return r ;
    }
    
    void build ( int o , int l , int r ) {
    	T[o].clear () ;
    	if ( l == r ) return ;
    	int m = l + r >> 1 ;
    	build ( lson ) ;
    	build ( rson ) ;
    }
    
    void update ( int x , int p , int v , int o , int l , int r ) {
    	pii tmp ( x , p ) ;
    	if ( v ) T[o].insert ( pii ( x , p ) ) ;
    	else if ( T[o].find ( tmp ) != T[o].end () ) T[o].erase ( tmp ) ;
    	if ( l == r ) return ;
    	int m = l + r >> 1 ;
    	if ( p <= m ) update ( x , p , v , lson ) ;
    	else update ( x , p , v , rson ) ;
    }
    
    void query ( int L , int R , int h , int k , int o , int l , int r ) {
    	if ( L <= l && r <= R ) {
    		it = T[o].lower_bound ( pii ( h , -1 ) ) ;
    		for ( int i = 0 ; i < k && it != T[o].end () ; ++ it , ++ i ) {
    			a[++ cnt] = it->first ;
    		}
    		return ;
    	}
    	int m = l + r >> 1 ;
    	if ( L <= m ) query ( L , R , h , k , lson ) ;
    	if ( m <  R ) query ( L , R , h , k , rson ) ;
    }
    
    pii get_Hash ( int L , int R ) {
    	if ( L == 0 ) return pii ( h1[R] , h2[R] ) ;
    	int v = R - L + 1 ;
    	int v1 = ( h1[R] - 1LL * h1[L - 1] * p1[v] % P1 + P1 ) % P1 ;
    	int v2 = ( h2[R] - 1LL * h2[L - 1] * p2[v] % P2 + P2 ) % P2 ;
    	return pii ( v1 , v2 ) ;
    }
    
    void solve () {
    	mp1.clear () ;
    	mp2.clear () ;
    	mp3.clear () ;
    	n = strlen ( s ) ;
    	reverse ( s , s + n ) ;
    	h1[0] = s[0] ;
    	h2[0] = s[0] ;
    	for ( int i = 1 ; i < n ; ++ i ) {
    		h1[i] = ( 1LL * h1[i - 1] * seed + s[i] ) % P1 ;
    		h2[i] = ( 1LL * h2[i - 1] * seed + s[i] ) % P2 ;
    	}
    	da ( n + 1 , 128 ) ;
    	init_rmq ( n ) ;
    	build ( root ) ;
    	//for ( int i = 1 ; i <= n ; ++ i ) {
    	//	printf ( "%d " , sa[i] ) ;
    	//}
    	for ( int i = 0 ; i < q ; ++ i ) {
    		int op , x , p , k ;
    		scanf ( "%d%d%d" , &op , &x , &p ) ;
    		pii tmp ( x , p ) ;
    		p = n - p - 1 ;
    		pii val = get_Hash ( p , p + x - 1 ) ;
    		p = rnk[p] ;
    		//printf ( "%d %d %d
    " , op , x , p ) ;
    		if ( op == 1 ) {
    			//if ( mp3[tmp] ) continue ;
    			//mp3[tmp] = 1 ;
    			if(mp1[val])continue;
    			mp1[val] ++ ;
    			if ( mp1[val] == 1 ) {
    			        //puts("A");
    				mp2[val] = p ;
    				update ( x , p , 1 , root ) ;
    			}
    		} else if ( op == 2 ) {
    			//if ( mp3[tmp] == 0 ) continue ;
    			//mp3[tmp] = 0 ;
    			if ( mp1[val] == 0 ) continue ;
    			mp1[val] -- ;
    			if ( mp1[val] == 0 ) {
    			        //puts("B");
    				update ( x , mp2[val] , 0 , root ) ;
    			}
    		} else {
    			scanf ( "%d" , &k ) ;
    			int L = get_L ( x , 1 , p ) ;
    			int R = get_R ( x , p , n ) ;
    			cnt = 0 ;
    			query ( L , R , x , k , root ) ;
    			nth_element ( a + 1 , a + k , a + cnt + 1 ) ;
    			if ( cnt < k ) printf ( "-1
    " ) ;
    			else printf ( "%d
    " , a[k] ) ;
    		}
    	}
    }
    
    int main () {
    	p1[0] = p2[0] = 1 ;
    	for ( int i = 1 ; i < MAXN ; ++ i ) {
    		p1[i] = 1LL * p1[i - 1] * seed % P1 ;
    		p2[i] = 1LL * p2[i - 1] * seed % P2 ;
    	}
    	while ( ~scanf ( "%s%d" , s , &q ) ) solve () ;
    	return 0 ;
    }
    

      

    J. Joining Powers

    二分答案,计数则考虑容斥,因为只关心选取集合的$lcm$以及奇偶性,而且$lcm>64$时与$64$无异,所以设$dp[i][j]$表示考虑了前$i$个集合,准备容斥的部分的$lcm$为$j$的容斥系数,求出系数之后开根号统计即可。

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const ll inf=1e18;
    const int MAGIC=7;
    int n,m,cnt,i,j,a[55],b[55];
    int lc[90][90];
    ll f[20010][60];
    ll l,r,mid,ans;
    ll q[3000000];
    int cur;
    int gcd(int a,int b){return b?gcd(b,a%b):a;}
    int lcm(int a,int b){return a*b/gcd(a,b);}
    inline ll cal2(ll a,int b){
      ll t=1;
      while(b--){
        if(t>inf/a)return inf;
        t*=a;
      }
      return t;
    }
    inline ll cal(ll a,int b){
      ll t=1;
      bool flag=0;
      while(b){
        if(b&1){
          if(flag)return inf;
          if(t>inf/a)return inf;
          t*=a;
        }
        b>>=1;
        if(a>inf/a)flag=1;
        if(!flag)a*=a;
      }
      return t;
    }
    inline ull ask(int k,ll lim){
      ll l=1,r=lim,mid,t=0;
      while(l<=r){
        mid=(l+r)>>1;
        if(cal(mid,k)<=lim)l=(t=mid)+1;else r=mid-1;
      }
      return t;
    }
    inline ull askfast(int k,ll lim){
      double t=pow(lim,1.0/k);
      ll x=(ll)(t);
      x=max(0LL,x);
      while(cal(x+1,k)<=lim)x++;
      while(x>0&&cal(x,k)>lim)x--;
      return 1ULL*x;
    }
    inline bool ispower(ll x,int k){
      ll l=1,r=x,mid;
      while(l<=r){
        mid=(l+r)>>1;
        ll t=cal(mid,k);
        if(t==x)return 1;
        if(t<x)l=mid+1;else r=mid-1;
      }
      return 0;
    }
    ull dp[55][70];
    ull check(ll mid){
      int i,j,k;
      for(i=0;i<=m;i++)for(j=1;j<64;j++)dp[i][j]=0;
      dp[0][1]-=1;
      for(i=0;i<m;i++)for(j=1;j<64;j++)if(dp[i][j]){
        dp[i+1][j]+=dp[i][j];
        dp[i+1][min(63,lc[j][a[i+1]])]-=dp[i][j];
      }
      ull ret=0;
      for(i=2;i<64;i++)if(dp[m][i]){
        //printf("%d %llu
    ",i,dp[m][i]);
        ret+=dp[m][i]*askfast(i,mid);
      }
      /*cur=0;
      for(i=0;i<m;i++)if(a[i]>MAGIC){
        for(j=1;;j++){
          ll t=f[j][a[i]];
          if(t>mid)break;
          q[++cur]=t;
        }
      }
      sort(q+1,q+cur+1);
      ull ret=0;
      for(i=1;i<=cur;i++)if(i==1||q[i]!=q[i-1]){
        for(k=0;k<cnt;k++)if(ispower(q[i],b[k]))break;
        if(k==cnt)ret++;
      }
      int S;
      for(S=1;S<1<<cnt;S++){
        int o=1;
        for(i=0;i<cnt;i++)if(S>>i&1)o=lcm(o,b[i]);
        if(__builtin_popcount(S)&1)ret+=ask(o,mid);else ret-=ask(o,mid);
      }*/
      return ret;
    }
    ll solve(){
      scanf("%d%d",&n,&m);
      cnt=0;
      for(i=1;i<=m;i++){
        scanf("%d",&a[i]);
        //if(a[i]<=MAGIC)b[cnt++]=a[i];
      }
      for(i=1;i<=m;i++)if(a[i]==1)return n;
      l=1,r=100000000000000009LL;
      while(l<r){
        mid=(l+r)>>1;
        if(check(mid)>=n)r=mid;else l=mid+1;
      }
      return l;
    }
    int main(){
      int T;
      for(i=1;i<90;i++)for(j=1;j<90;j++)lc[i][j]=lcm(i,j);
      //for(i=1;i<=20000;i++)for(j=1;j<=50;j++)f[i][j]=cal(i,j);
      for(scanf("%d",&T);T--;printf("%lld
    ",solve()));
      return 0;
    }
    

      

    K. Keyboard Map

    $f[i][j]$表示前$j$个数划分成$i$段的最小花费,转移显然具有决策单调性,分治求解即可。时间复杂度$O(nmlog n)$。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1000010;
    typedef long long LL;
    const int Maxn=1000020;
    const LL Inf=1LL<<60;
    LL sum1[5050],sum2[5050];
    LL a[5050];
    int n,k;
    LL f[3030][5050];
    int O;
    LL cal(int l,int r){
    	return sum1[r]-sum1[l]-(sum2[r]-sum2[l])*l;
    }
    void solve(int l,int r,int dl,int dr){
      int m=(l+r)>>1,dm=dl;
      LL&t=f[O][m];
      t=Inf;
      for(int i=dl;i<=dr&&i<m;i++){
        LL now=f[O-1][i]+cal(i,m);
        if(now<t)t=now,dm=i;
      }
      if(l<m)solve(l,m-1,dl,dm);
      if(r>m)solve(m+1,r,dm,dr);
    }
    int main(){
    	while(scanf("%d%d",&n,&k)!=EOF){
    		for(int i=1;i<=n;i++){
    			scanf("%lld",a+i);
    			sum1[i]=sum1[i-1]+i*a[i];
    			sum2[i]=sum2[i-1]+a[i];
    		}
    		//printf("cal33=%lld
    ",cal(2,3));
    		for(int j=0;j<=n;j++)
    				f[1][j]=sum1[j];
    		for(O=2;O<=k;O++){
    		  solve(O,n,O-1,n);
                    }
    			/*	else{
    					f[i][j]=Inf;
    					for(int bef=0;bef<j;bef++){
    						f[i][j]=min(f[i][j],f[i-1][bef]+cal(bef,j));
    					}
    				}
    			}
    		}*/
    		//printf("f23=%lld
    ",f[2][3]);
    		printf("%lld
    ",f[k][n]);
    	}
    }
    

      

    L. Light Sources

    显然当选出来的多边形是个凸包时,周长最小。

    枚举起点,然后极角排序,设$dp[i][j]$表示选取的最后一个点是$i$,选中的颜色集合为$j$的最小周长,然后枚举下一个凸包上的点转移即可。

    时间复杂度$O(m^32^k)$。

    #include<bits/stdc++.h>
    using namespace std ;
    
    typedef long long LL ;
    
    #define clr( a , x ) memset ( a , x , sizeof a )
    
    const int MAXN = 305 ;
    
    struct P {
    	LL x , y ;
    	P () {}
    	P ( LL x , LL y ) : x ( x ) , y ( y ) {}
    	LL operator * ( const P& p ) const {
    		return x * p.y - y * p.x ;
    	}
    	P operator + ( const P& p ) const {
    		return P ( x + p.x , y + p.y ) ;
    	}
    	P operator - ( const P& p ) const {
    		return P ( x - p.x , y - p.y ) ;
    	}
    	bool operator < ( const P& p ) const {
    		return x != p.x ? x < p.x : y < p.y ;
    	}
    	double len () {
    		return sqrt ( x * x + y * y ) ;
    	}
    	double angle () {
    		return atan2 ( y , x ) ;
    	}
    } ;
    
    struct Node {
    	double r ;
    	int idx ;
    	bool operator < ( const Node& a ) const {
    		return r < a.r ;
    	}
    } ;
    
    P p[MAXN] , q[MAXN] ;
    double len[MAXN][MAXN] ;
    double dp[MAXN][1 << 7] ;
    int val[MAXN][MAXN] ;
    Node a[MAXN] ;
    int c[MAXN] ;
    double ans ;
    int n , m , K ;
    
    int dcmp ( LL x ) {
    	if ( x ) return x > 0 ? 1 : -1 ;
    	return 0 ;
    }
    
    bool PointInTri ( P& i , P& j , P& k , P& l ) {
    	int a = dcmp ( ( i - l ) * ( j - l ) ) ;
    	int b = dcmp ( ( j - l ) * ( k - l ) ) ;
    	int c = dcmp ( ( k - l ) * ( i - l ) ) ;
    	return a * b > 0 && b * c > 0 && c * a > 0 ;
    }
    
    void calc ( int m ) {
    	int tot = 1 << K ;
    	for ( int i = 0 ; i <= m ; ++ i ) {
    		for ( int j = 0 ; j < tot ; ++ j ) {
    			dp[i][j] = 1e60 ;
    		}
    		for ( int j = 0 ; j <= m ; ++ j ) {
    			len[i][j] = ( p[a[i].idx] - p[a[j].idx] ).len () ;
    		}
    	}
    	for ( int i = 1 ; i <= m ; ++ i ) {
    		for ( int j = i + 1 ; j <= m ; ++ j ) {
    			val[i][j] = 0 ;
    			for ( int l = 0 ; l < n ; ++ l ) {
    				if ( PointInTri ( p[a[0].idx] , p[a[i].idx] , p[a[j].idx] , q[l] ) ) {
    					val[i][j] |= 1 << c[l] ;
    				}
    			}
    		}
    	}
    	for ( int i = 1 ; i <= m ; ++ i ) {
    		dp[i][0] = len[0][i] * 2 ;
    		for ( int s = 0 ; s < tot ; ++ s ) {
    			for ( int k = 1 ; k < i ; ++ k ) if ( dp[k][s] < 1e50 ) {
    				int nxt = s | val[k][i] ;
    				dp[i][nxt] = min ( dp[i][nxt] , dp[k][s] + len[0][i] + len[k][i] - len[0][k] ) ;
    			}
    		}
    		ans = min ( ans , dp[i][tot - 1] ) ;
    	}
    }
    
    void solve () {
    	for ( int i = 0 ; i < n ; ++ i ) {
    		scanf ( "%lld%lld" , &q[i].x , &q[i].y ) ;
    	}
    	for ( int i = 0 ; i < n ; ++ i ) {
    		scanf ( "%d" , &c[i] ) ;
    		c[i] -- ;
    	}
    	for ( int i = 1 ; i <= m ; ++ i ) {
    		scanf ( "%lld%lld" , &p[i].x , &p[i].y ) ;
    	}
    	ans = 1e60 ;
    	sort ( p + 1 , p + m + 1 ) ;
    	for ( int i = 1 ; i <= m ; ++ i ) {
    		int cnt = 0 ;
    		for ( int j = i + 1 ; j <= m ; ++ j ) {
    			++ cnt ;
    			a[cnt].idx = j ;
    			a[cnt].r = ( p[j] - p[i] ).angle () ;
    		}
    		a[0].idx = i ;
    		sort ( a + 1 , a + cnt + 1 ) ;
    		calc ( cnt ) ;
    	}
    	if ( ans < 1e50 ) printf ( "%.12f
    " , ans ) ;
    	else printf ( "-1
    " ) ;
    }
    
    int main () {
    	while ( ~scanf ( "%d%d%d" , &n , &m , &K ) ) solve () ;
    	return 0 ;
    }
    

      

    M. Merging

    不断用堆取出最小的$k$项即可。

    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>P;
    typedef pair<ll,P>PI;
    int n,K,i,j,a[30010][8];ll ans,lim=1e18;
    priority_queue<PI,vector<PI>,greater<PI> >q;
    inline void ext(int o,int x){
      ll t=0;
      for(int i=7;~i;i--){
        if(t>lim/x)return;
        t=t*x+a[o][i];
        if(t>lim)return;
      }
      q.push(PI(t,P(o,x)));
    }
    int main(){
      scanf("%d",&n);
      for(i=1;i<=n;i++)for(j=7;~j;j--)scanf("%d",&a[i][j]);
      scanf("%d",&K);
      for(i=1;i<=n;i++)ext(i,1);
      while(K--){
        PI t=q.top();q.pop();
        ans=t.first;
        ext(t.second.first,t.second.second+1);
      }
      printf("%lld",ans);
    }
    

      


    总结:

    • J题对一开始的算法时间复杂度分析错误,致使4次TLE。
    • F题偷懒用__int128结果WA,下次要注意。
  • 相关阅读:
    牛客寒假算法基础集训营1 C 小a与星际探索(思维+异或)
    牛客寒假算法基础集训营4 E Applese 涂颜色
    Python的range()函数用法
    R语言读取XML数据
    R语言如何读取.csv文件
    反转链表
    HashSet HashTable HashMap 区别
    输入两个整数 n 和 m,从数列1,2,3.......n 中随意取几个数,使其和等于 m ,要求将其中所有的可能组合列出来.
    Activity生命周期之我见
    左旋转字符串
  • 原文地址:https://www.cnblogs.com/clrs97/p/6075379.html
Copyright © 2011-2022 走看看