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(n\log 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\n", i, a[i]);
	}
	//puts("finish");
}
int main()
{
	init();
	table();
	scanf("%d", &n);
	printf("%d\n", a[n]);
	return 0;
}
/*
【trick&&吐槽】


【题意】


【分析】


【时间复杂度&&优化】


*/

  

D. Brand registration

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

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

时间复杂度$O(n^2\log 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\n", 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\n",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\n",A,B,C,D,w);
					//if(x!=1)
					//if(x==1)printf("! %d %d %d %d %d\n",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\n",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\n",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\n", 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\n", ans);
		}
	}
	return 0;
}
/*
【trick&&吐槽】

5 6
9 1 2 999999993

85 155
88 120 53 980090303

【题意】


【分析】


【时间复杂度&&优化】


*/

  

H. A$+$B

$\lfloor\frac{s}{2}\rfloor$与$s-\lfloor\frac{s}{2}\rfloor$是一组合法解。

#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\times 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\n",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\n",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\n",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\n",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

留坑。

posted @ 2018-04-11 00:36 Claris 阅读(...) 评论(...) 编辑 收藏