zoukankan      html  css  js  c++  java
  • Lesnoe Ozero 2016. BSUIR Open 2016 Finals

    A. Street magic

    数位DP,设$f[i][j][k]$表示从低到高考虑$x$的后$i$位,$x$和$m$大小关系为$j$,和$n$大小关系为$k$的方案数。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int N=80,P=1000000007;
    char a[N],b[N];
    int n,m,i,j,k,x,lim,f[N][2][2];
    /*
    0:=m
    1:>m
    
    0:<=n
    1:>n
    */
    inline void up(int&a,int b){a=a+b<P?a+b:a+b-P;}
    int main(){
    	scanf("%s%s",a+1,b+1);
    	n=strlen(a+1);
    	m=strlen(b+1);
    	reverse(a+1,a+n+1);
    	reverse(b+1,b+m+1);
    	lim=max(n,m)+1;
    	a[0]=b[0]=0;
    	for(i=1;i<=n;i++)a[i]-='0';
    	for(i=n+1;i<=lim;i++)a[i]=0;
    	for(i=1;i<=m;i++)b[i]-='0';
    	for(i=m+1;i<=lim;i++)b[i]=0;
    	
    	f[0][0][0]=1;
    	for(i=0;i<lim;i++)for(j=0;j<2;j++)for(k=0;k<2;k++)if(f[i][j][k]){
    		for(x=0;x<10;x++){
    			int nj,nk;
    			if(x<b[i+1])continue;
    			if(x==b[i+1]){
    				nj=j;
    			}else nj=1;
    			if(x==a[i+1]){
    				nk=k;
    			}else{
    				if(x>a[i+1])nk=1;
    				else nk=0;
    			}
    			up(f[i+1][nj][nk],f[i][j][k]);
    		}
    	}
    	
    	printf("%d",(f[lim][0][0]+f[lim][1][0])%P);
    }
    

      

    B. Variety

    对于每种颜色单独考虑,从上往下扫描线,用Treap维护每个点往上延伸的高度的笛卡尔树,则每次只需要单点修改或者整体加。

    因为数据随机,所以高度随机,直接用高度当优先级复杂度就是正确的。

    为了应对多种颜色,应当按时间顺序记录Treap的每次修改以方便还原。

    这个做法在$k=1$时会退化,但是当$k=1$时显然$ans=1$,故特判即可。

    #include<cstdio>
    #include<algorithm>
    #include<cstdlib>
    #include<vector>
    using namespace std;
    const int N=1010;
    int o;
    int root,r,c,n,i,j,initroot;
    int flag;
    int mx;
    int cnt;
    long long ans;
    struct P{int x,y;P(){}P(int _x,int _y){x=_x,y=_y;}}x,y;
    struct E{int c,x,y;E(){}E(int _c,int _x,int _y){c=_c,x=_x,y=_y;}}a[1000010];
    inline bool cmp(const E&a,const E&b){return a.c==b.c?a.x<b.x:a.c<b.c;}
    namespace Treap{
    const int M=20000010;
    int h[N],l[N],r[N],size[N],tag[N],sum[N];
    int q[M][2];
    char w[M];
    int top;
    inline void push(int x,int y,int z){
      if(flag)return;
      top++;
      if(top>mx)mx=top;
      w[top]=x;
      q[top][0]=y;
      q[top][1]=z;
    }
    inline void rec(){
      int x=w[top],y=q[top][0],z=q[top][1];
      top--;
      if(x==0)h[y]=z;
      if(x==1)l[y]=z;
      if(x==2)r[y]=z;
      if(x==3)size[y]=z;
      if(x==4)tag[y]=z;
      if(x==5)sum[y]=z;
    }
    inline void up(int x){
      push(3,x,size[x]);
      push(5,x,sum[x]);
      size[x]=size[l[x]]+size[r[x]]+1;
      sum[x]=sum[l[x]]+sum[r[x]]+((h[l[x]]-h[x])*size[l[x]]*(size[l[x]]+1)>>1)+((h[r[x]]-h[x])*size[r[x]]*(size[r[x]]+1)>>1);
    }
    inline void add(int x,int p){
      if(!x)return;
      push(0,x,h[x]);
      push(4,x,tag[x]);
      h[x]+=p;tag[x]+=p;
    }
    inline void pb(int x){
      if(tag[x]){
        add(l[x],tag[x]),add(r[x],tag[x]);
        push(4,x,tag[x]);
        tag[x]=0;
      }
    }
    P split(int x,int y){
      if(!x)return P(0,0);
      pb(x);
      if(size[l[x]]+1<=y){
        P t=split(r[x],y-size[l[x]]-1);
        push(2,x,r[x]);
        return r[x]=t.x,up(x),P(x,t.y);
      }
      P t=split(l[x],y);
      push(1,x,l[x]);
      return l[x]=t.y,up(x),P(t.x,x);
    }
    int merge(int x,int y){
      if(!x)return y;
      if(!y)return x;
      pb(x),pb(y);
      if(h[x]<h[y]){
        int z=merge(r[x],y);
        push(2,x,r[z]);
        return r[x]=z,up(x),x;
      }
      int z=merge(x,l[y]);
      push(1,y,l[y]);
      return l[y]=z,up(y),y;
    }
    int build(int a,int b){
      if(a>b)return 0;
      int mid=(a+b)>>1;
      l[mid]=build(a,mid-1);
      r[mid]=build(mid+1,b);
      up(mid);
      return mid;
    }
    }
    inline void go(int k){
      if(k<=0)return;
      ans-=1LL*Treap::sum[root]*k;
      long long tmp=1LL*Treap::size[root]*(Treap::size[root]+1)/2;
      long long st=Treap::h[root];
      ans-=1LL*(st*2+k+1)*k/2*tmp;
      Treap::add(root,k);
    }
    inline void init(){
      flag=1;
      Treap::top=0;
      for(root=i=0;i<=c;i++)Treap::h[i]=Treap::l[i]=Treap::r[i]=Treap::size[i]=Treap::tag[i]=Treap::sum[i]=0;
      /*
      root=r;Treap::up(r);
      for(i=r-1;i;i--){
        Treap::r[i]=i+1;
        Treap::up(i);
      }*/
      //root=1;
      root=Treap::build(1,r);
      flag=0;
      initroot=root;
    }
    inline void solve(int L,int R){
      int i,j,k;
      ans+=1LL*r*(r+1)*c*(c+1)>>2;
      flag=(R-L)>r;
      int pre=0;
      for(i=L;i<=R;i=j){
        for(j=i;j<=R&&a[i].x==a[j].x;j++);
        go(a[i].x-pre-1);
        pre=a[i].x;
        Treap::add(root,1);
        for(k=i;k<j;k++){
          x=Treap::split(root,a[k].y-1),y=Treap::split(x.y,1);
          Treap::push(0,y.x,Treap::h[y.x]);
          Treap::h[y.x]=0;
          root=Treap::merge(Treap::merge(x.x,y.x),y.y);
        }
        ans-=Treap::sum[root]+((1LL*Treap::h[root]*Treap::size[root]*(Treap::size[root]+1))>>1);
      }
      go(r-pre);
      if(flag)init();
      else{
        root=initroot;
        while(Treap::top)Treap::rec();
      }
    }
    int main(){
      scanf("%d",&r);c=r;
      for(i=1;i<=r;i++)for(j=1;j<=c;j++){
        scanf("%d",&o);
        //o=rand()%(r*c)+1;
        a[++n]=E(o,i,j);
      }
      std::sort(a+1,a+n+1,cmp);
      if(a[1].c==a[n].c)return puts("1"),0;
      ans=0;
      init();
      for(i=1;i<=n;i=j){
        for(j=i;j<=n&&a[i].c==a[j].c;j++);
        solve(i,j-1);
      }
      long long all=1LL*r*(r+1)*c*(c+1)/4;
      double fin=1.0*ans/all;
      printf("%.15f",fin);
    }
    

      

    C. Crime fiction society

    利用线性筛的预处理在$O(log n)$的时间内分解质因数,同时对于每个质数$p$记录它最小的可能没被占据的倍数,然后暴力枚举即可,时间复杂度$O(nlog n)$。

    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<string>
    #include<ctype.h>
    #include<math.h>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    #include<bitset>
    #include<algorithm>
    #include<time.h>
    using namespace std;
    void fre() {  }
    #define MS(x, y) memset(x, y, sizeof(x))
    #define ls o<<1
    #define rs o<<1|1
    typedef long long LL;
    typedef unsigned long long UL;
    typedef unsigned int UI;
    template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
    template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
    const int N = 1e7 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
    template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
    int casenum, casei;
    int n;
    int a[N], vis[N], nxt[N];
    //
    int tot,i,j,p[N/8],v[N];
    inline int divide(int n){
    	int ans = 1e9;
    	while(n>1){
    		int x=v[n];
    		n/=x;
    		while(vis[nxt[x]])
    		{
    			nxt[x] += x;
    			/*if(nxt[x] > 1e7)
    			{
    				puts("NO");
    				while(1);
    			}*/
    		}
    		ans = min(ans, nxt[x]);
    	}
    	return ans;
    }
    void init(){
    	vis[0] = 1;
    	int top = 1e7;
    	for(i=2;i<=top;i++){
    		if(!v[i])v[p[tot++]=i]=i;
    		for(j=0;j<tot&&1LL*i*p[j]<=top;j++){
    			v[i*p[j]]=p[j];
    			if(i%p[j]==0)break;
    		}
    	}
    }
    //
    void table()
    {
    	int top = 3e6;
    	a[1] = 1; vis[1] = 1;
    	a[2] = 2; vis[2] = 1;
    	for(int i = 3; i <= top; ++i)
    	{
    		a[i] = divide(a[i - 1]);
    		vis[a[i]] = 1;
    		//printf("%d %d
    ", i, a[i]);
    	}
    	//puts("finish");
    }
    int main()
    {
    	init();
    	table();
    	scanf("%d", &n);
    	printf("%d
    ", a[n]);
    	return 0;
    }
    /*
    【trick&&吐槽】
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

    D. Brand registration

    设$f[i][j][k]$表示从某个点开始转了$k$次弯,最后一条线段是$i ightarrow j$的方案数,则需要转移到与$i$夹角小于$90°$的所有点。

    枚举每个$j$,将所有点关于$j$极角排序,那么每次转移都是一个区间,前缀和优化即可。

    时间复杂度$O(n^2log n)$。

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=1010;
    const double pi2=acos(-1.0)*2.0,pi=acos(-1.0)/2.0,eps=1e-8;
    int n,m,i,j,k,q[N*2];ll f[N][N],g[N][N],ans;
    double b[N],c[N*2];
    ll s[N*2];
    struct P{
    	int x,y;
    }a[N];
    inline bool cmp(int x,int y){
    	return b[x]<b[y];
    }
    void dpleft(){
    	for(i=1;i<=n;i++)for(j=1;j<=n;j++)g[i][j]=0;
    	for(i=1;i<=n;i++){
    		m=0;
    		for(j=1;j<=n;j++)if(i!=j){
    			b[j]=atan2(a[j].y-a[i].y,a[j].x-a[i].x);
    			q[++m]=j;
    		}
    		sort(q+1,q+m+1,cmp);//counter clock wise
    		for(j=1;j<=m;j++){
    			c[j]=b[q[j]];
    			c[j+m]=c[j]+pi2;
    			q[j+m]=q[j];
    		}
    		for(j=1;j<=m*2;j++)s[j]=s[j-1]+f[q[j]][i];
    		for(j=m,k=m*2;j;j--){
    			k=min(k,j+m-1);
    			while(k>j&&c[k]-c[j]+eps>pi)k--;
    			g[i][q[j]]+=s[k]-s[j];
    		}
    	}
    	for(i=1;i<=n;i++)for(j=1;j<=n;j++)f[i][j]=g[i][j];
    }
    void dpright(){
    	for(i=1;i<=n;i++)for(j=1;j<=n;j++)g[i][j]=0;
    	for(i=1;i<=n;i++){
    		m=0;
    		for(j=1;j<=n;j++)if(i!=j){
    			b[j]=atan2(a[j].y-a[i].y,a[j].x-a[i].x);
    			q[++m]=j;
    		}
    		sort(q+1,q+m+1,cmp);//counter clock wise
    		for(j=1;j<=m;j++){
    			c[j]=b[q[j]];
    			c[j+m]=c[j]+pi2;
    			q[j+m]=q[j];
    		}
    		for(j=1;j<=m*2;j++)s[j]=s[j-1]+f[q[j]][i];
    		for(j=m+1,k=1;j<=m*2;j++){
    			k=max(k,j-m+1);
    			while(k<j&&c[j]-c[k]+eps>pi)k++;
    			g[i][q[j]]+=s[j-1]-s[k-1];
    		}
    	}
    	for(i=1;i<=n;i++)for(j=1;j<=n;j++)f[i][j]=g[i][j];
    }
    int main(){
    	scanf("%d",&n);
    	for(i=1;i<=n;i++)scanf("%d%d",&a[i].x,&a[i].y);
    	for(i=1;i<=n;i++)for(j=1;j<=n;j++)if(i!=j)f[i][j]=1;
    	dpleft();
    	dpright();
    	dpleft();
    	dpright();
    	for(i=1;i<=n;i++)for(j=1;j<=n;j++)if(i!=j)ans+=f[i][j];
    	printf("%lld",ans/2);
    }
    

      

    E. Elections

    设$f[n]$表示$n$个人至少需要多少票,枚举因子转移。

    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<string>
    #include<ctype.h>
    #include<math.h>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    #include<bitset>
    #include<algorithm>
    #include<time.h>
    using namespace std;
    void fre() {  }
    #define MS(x, y) memset(x, y, sizeof(x))
    #define ls o<<1
    #define rs o<<1|1
    typedef long long LL;
    typedef unsigned long long UL;
    typedef unsigned int UI;
    template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
    template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
    const int N = 1e5 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
    template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
    int casenum, casei;
    int n;
    const int INF = 1e9;
    int f[N];
    int a[N];
    int m;
    
    int main()
    {
    	while(~ scanf("%d", &n)){
    		m = 0;
    		for(int i = 1; i * i <= n; i ++){
    			if(n % i == 0){
    				a[++ m] = i;
    				if(i * i != n) a[++ m] = n / i;
    			}
    		}
    		sort(a + 1, a + m + 1);
    		for(int i = 1; i <= m; i ++) f[i] = INF;
    		
    		for(int i = 1; i <= m; i ++){
    			f[i] = a[i] / 2 + 1;
    			for(int j = 1; j < i; j ++){
    				if(a[i] % a[j] == 0){	// 每份个数
    					f[i] = min(f[i], f[j] * (a[i] / a[j] / 2 + 1));
    				}
    			} 
    		}
    		printf("%d
    ", f[m]);
    	}
    	return 0;
    }
    /*
    【trick&&吐槽】
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

    F. Cactus

    因为是仙人掌,所以每条边最多属于一个环。

    设$f[i][j][k][S]$表示考虑DFS生成树上$i$点的子树,$i$点所在连通块边数为$j$,$i$点到$i$父亲这条边所在环底部的点所在连通块边数为$k$,$i$与环底部的点连通情况为$S$的方案数,分$3$种情况转移即可。

    时间复杂度$O(n+m)$。

    #include<cstdio>
    #define rep(i) for(int i=0;i<3;i++)
    #define FOR(i) for(int i=0;i<2;i++)
    const int N=100010,M=200010,P=1000000007;
    int n,m,i,x,y,g[N],v[M<<1],nxt[M<<1],ed;
    int vis[N],dfn,fa[N];
    int isbot[N],istop[N],in[N];
    int f[N][3][3][2];
    int dp[3][3][2],tmp[3][3][2];//connect with down?
    int ans;
    inline void up(int&a,int b){a=a+b<P?a+b:a+b-P;}
    inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
    inline void clr(){
    	rep(i)rep(j)FOR(k)tmp[i][j][k]=0;
    }
    inline void go(){
    	rep(i)rep(j)FOR(k)dp[i][j][k]=tmp[i][j][k];
    }
    void dfs(int x,int y){
    	fa[x]=y;
    	vis[x]=++dfn;
    	//printf("fa[%d]=%d
    ",x,y);
    	for(int i=g[x];i;i=nxt[i]){
    		int u=v[i];
    		if(u==y)continue;
    		if(!vis[u]){
    			dfs(u,x);
    		}else if(vis[u]<vis[x]){
    			int j=x;
    			isbot[x]=1;
    			while(j!=u){
    				if(fa[j]==u)istop[j]=1;
    				in[j]=1;
    				j=fa[j];
    			}
    		}
    	}
    	clr();
    	go();
    	dp[0][0][0]=1;
    	for(int i=g[x];i;i=nxt[i]){
    		int u=v[i];
    		if(fa[u]!=x)continue;
    		clr();
    		if(istop[u]){
    			rep(A)rep(B)FOR(k)if(dp[A][B][k])rep(C)rep(D)FOR(l)if(f[u][C][D][l]){
    				int w=1LL*dp[A][B][k]*f[u][C][D][l]%P;
    				//not choose (x,u) not choose ex
    				up(tmp[A][B][k],w);
    				//not choose (x,u) choose ex
    				if(A+D+1<3){
    					//if(A+D+1==2&&x==1)printf("! %d %d %d %d %d
    ",A,B,C,D,w);
    					//if(x!=1)
    					//if(x==1)printf("! %d %d %d %d %d
    ",A,B,C,D,w);
    					up(tmp[A+D+1][B][k],w);
    				}
    				//choose(x,u) not choose ex
    				if(A+C+1<3)up(tmp[A+C+1][B][k],w);
    				//choose(x,u) choose ex
    				if(A+C+D+2<3){
    					//if(x==1)printf("! %d %d %d %d %d
    ",A,B,C,D,w);
    					up(tmp[A+C+D+2][B][k],w);
    				}
    			}
    		}else if(in[u]){//same circle
    			rep(A)rep(B)FOR(k)if(dp[A][B][k])rep(C)rep(D)FOR(l)if(f[u][C][D][l]){
    				int w=1LL*dp[A][B][k]*f[u][C][D][l]%P;
    				//not choose(x,u)
    				up(tmp[A][D][0],w);
    				//choose(x,u)
    				if(A+C+1<3){
    					up(tmp[A+C+1][D][l],w);
    				}
    			}
    		}else{
    			rep(A)rep(B)FOR(k)if(dp[A][B][k])rep(C)rep(D)FOR(l)if(f[u][C][D][l]){
    				int w=1LL*dp[A][B][k]*f[u][C][D][l]%P;
    				//not choose(x,u)
    				up(tmp[A][B][k],w);
    				//choose(x,u)
    				if(A+C+1<3)up(tmp[A+C+1][B][k],w);
    			}
    		}
    		go();
    	}
    	clr();
    	rep(A)rep(B)FOR(k)if(dp[A][B][k])up(tmp[A][k?A:B][k],dp[A][B][k]);
    	go();
    	if(isbot[x])rep(i)f[x][i][i][1]=dp[i][0][0];
    	else rep(i)rep(j)FOR(k)f[x][i][j][k]=dp[i][j][k];
    	//rep(i)rep(j)if(f[x][i][j])printf("f[%d][%d][%d]=%d
    ",x,i,j,f[x][i][j]);
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(ed=i=1;i<=m;i++){
    		scanf("%d%d",&x,&y);
    		add(x,y),add(y,x);
    	}
    	dfs(1,0);
    	rep(i)FOR(j)up(ans,f[1][i][0][j]);
    	printf("%d",ans);
    }
    /*
    5 5
    1 2
    3 4
    5 4
    3 2
    3 1
    
    
    4 4
    1 2
    1 3
    2 3
    3 4
    */
    

      

    G. Hard exam

    分$n$小和$n$大设计两种处理方法即可。

    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<string>
    #include<ctype.h>
    #include<math.h>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    #include<bitset>
    #include<algorithm>
    #include<time.h>
    using namespace std;
    void fre() {  }
    #define MS(x, y) memset(x, y, sizeof(x))
    #define ls o<<1
    #define rs o<<1|1
    typedef long long LL;
    typedef unsigned long long UL;
    typedef unsigned int UI;
    template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
    template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
    const int N = 1e7 + 10, M = 0, inf = 0x3f3f3f3f;
    int casenum, casei;
    
    int n, t;
    set<int> sot;
    set<int> :: iterator it;
    int q0, a, b, m, k;
    const int top = 3e3;
    int c[N];
    
    int main()
    {
    	while(~ scanf("%d%d", &n, &t)){
    		scanf("%d%d%d%d", &q0, &a, &b, &m);
    		LL Z = 1LL * n * n + 1;
    		if(n >= top){
    			int ans = 0;
    			for(int i = 1; i <= t; i ++){
    				q0 = (1LL * q0 * a + b) % m;
    				k = q0 % Z;
    				for(int j = 0; j <= n; j ++){
    					LL x = 1LL * k - 1LL * n * n + 1LL * j * n;
    					LL y = 2LL * j - n;
    					if(y && x % y == 0 && x / y <= n && x / y >= 0 || x == 0 && y == 0) {ans ++; break;}
    				}
    			}
    			printf("%d
    ", ans);
    		}
    		else{
    			int siz = 0;
    			for(int i = 0; i <= n; i ++){
    				for(int j = i; j <= n; j ++){
    					c[++ siz] = 1LL * n * n + 2 * i * j - (i + j) * n;
    				}
    			}
    			sort(c + 1, c + siz + 1);
    			int ans = 0;
    			for(int i = 1; i <= t; i ++){
    				q0 = (1LL * q0 * a + b) % m;
    				k = q0 % Z;
    				if(*lower_bound(c + 1, c + siz + 1, k) == k) ans ++;
    			}
    			printf("%d
    ", ans);
    		}
    	}
    	return 0;
    }
    /*
    【trick&&吐槽】
    
    5 6
    9 1 2 999999993
    
    85 155
    88 120 53 980090303
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

    H. A$+$B

    $lfloorfrac{s}{2} floor$与$s-lfloorfrac{s}{2} floor$是一组合法解。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    ll s,m;
    int main(){
    	scanf("%lld",&s);
    	m=s/2;
    	printf("%lld %lld",m,s-m);
    }
    

      

    I. Credit history

    可以看成$2n$个位置,每个位置有一个权值,要求按一些顺序博弈着给这些位置填数,使得每个位置的数字乘以权值之和最大/最小。

    设$f[S]$表示还剩$S$集合的位置没有填数,目前是银行在行动时,计算结果的最大可能值。

    设$g[S][k]$表示还剩$S$集合的位置没有填数,银行要求还债人填数字$k$,目前是还债人在行动时,计算结果的最小可能值。

    DP求出$f$和$g$后每次按照最优转移行动即可。

    时间复杂度$O(10n imes 4^n)$。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const ll inf=1LL<<60;
    int me,n,m,i,j,k;
    ll p[100],w[100];
    ll f[1<<18],g[1<<18][10];
    bool vf[1<<18],vg[1<<18][18];
    ll calf(int S);
    ll calg(int S,int o){
    	if(vg[S][o])return g[S][o];
    	vg[S][o]=1;
    	ll ret=inf;
    	for(int i=0;i<m;i++)if(S>>i&1)ret=min(ret,calf(S^(1<<i))+o*w[i]);
    	return g[S][o]=ret;
    }
    ll calf(int S){
    	if(!S)return 0;
    	if(vf[S])return f[S];
    	vf[S]=1;
    	ll ret=-inf;
    	for(int i=0;i<10;i++)ret=max(ret,calg(S,i));
    	return f[S]=ret;
    }
    int getpos(int x,int y){
    	y=n-y;
    	if(x==1)return y;
    	return y+n;
    }
    void write(int S){
    	printf("%d %d
    ",S/n+1,n-S%n);
    	fflush(stdout);
    }
    int main(){
    	scanf("%d%d",&me,&n);
    	for(p[0]=i=1;i<=n;i++)p[i]=p[i-1]*10;
    	for(i=0;i<n;i++)w[m++]=p[i];
    	for(i=0;i<n;i++)w[m++]=-p[i];
    	//for(i=0;i<m;i++)printf("%lld
    ",w[i]);
    	int S=(1<<m)-1;
    	for(int round=n*2;round--;){
    		if(me==1){//bank
    			ll ret=-inf;
    			for(i=0;i<10;i++)ret=max(ret,calg(S,i));
    			for(i=0;i<10;i++)if(calg(S,i)==ret){
    				printf("%d
    ",i);
    				fflush(stdout);
    				break;
    			}
    			int x,y;
    			scanf("%d%d",&x,&y);
    			S^=1<<getpos(x,y);
    		}else{
    			int x;
    			scanf("%d",&x);
    			ll ret=inf;
    			for(int i=0;i<m;i++)if(S>>i&1)ret=min(ret,calf(S^(1<<i))+x*w[i]);
    			//printf("->%lld
    ",ret);
    			for(int i=0;i<m;i++)if(S>>i&1)if(ret==calf(S^(1<<i))+x*w[i]){
    				write(i);
    				S^=1<<i;
    				break;
    			}
    		}
    	}
    }
    

      

    J. Cherry orchard

    留坑。

  • 相关阅读:
    Docker02 Docker初识:第一个Docker容器和Docker镜像
    Docker01 CentOS配置Docker
    Jenkins02:Jenkins+maven+svn集成
    Junit01 新建Maven项目
    Junit02 Junit创建及简单实现
    Jenkins01:linux+jenkins+ant+jmeter集成
    Jenkins初识03:构建定时任务
    python 协程
    python之socket 网络编程
    python 面向对象
  • 原文地址:https://www.cnblogs.com/clrs97/p/8785859.html
Copyright © 2011-2022 走看看