首页 > 代码库 > BestCoder Round #86 解题报告

BestCoder Round #86 解题报告

A.Price List

Sol

求和查询

Code

#include<cstdio>#include<algorithm>#include<iostream>using namespace std;typedef long long LL;const int N = 100005;//LL v[N];inline LL in(LL x=0,char ch=getchar()){ while(ch>‘9‘||ch<‘0‘) ch=getchar();    while(ch>=‘0‘&&ch<=‘9‘) x=(x<<3)+(x<<1)+ch-‘0‘,ch=getchar();return x; }int main(){    int T,n,m;LL tmp;    for(T=in();T--;){        n=in(),m=in(),tmp=0;        for(int i=1;i<=n;i++) tmp+=in();//        for(int i=1;i<=n;i++) v[i]=in();        for(int i=1;i<=m;i++){            if(in()>tmp) putchar(‘1‘);            else putchar(‘0‘);        }putchar(‘\n‘);    }return 0;}

 


B.NanoApe Loves Sequence

Sol

统计出来前面最大的绝对值,后面最大的绝对值,然后枚举中间位置就可以了.

Code

#include<cstdio>#include<iostream>using namespace std;const int N = 100005;int T,n,a[N],p[N],q[N];long long ans;//inline int in(int x=0,char ch=getchar()){ while(ch>‘9‘||ch<‘0‘) ch=getchar();//    while(ch>=‘0‘&&ch<=‘9‘) x=(x<<3)+(x<<1)+ch-‘0‘,ch=getchar();return x; }inline int abs(int x){ return x<0?-x:x; }int main(){    for(cin>>T;T--;){//        n=in();for(int i=1;i<=n;i++) a[i]=in();        scanf("%d",&n);        memset(a,0,sizeof(a));        memset(p,0,sizeof(p));        memset(q,0,sizeof(q));        for(int i=1;i<=n;i++) scanf("%d",&a[i]);        for(int i=2;i<=n;i++) p[i]=max(p[i-1],abs(a[i]-a[i-1]));        for(int i=n-1;i;i--) q[i]=max(q[i+1],abs(a[i]-a[i+1]));        //        for(int i=1;i<=n;i++) cout<<p[i]<<" ";cout<<endl;//        for(int i=1;i<=n;i++) cout<<q[i]<<" ";cout<<endl;                ans=q[2]+p[n-1];        for(int i=2;i<n;i++) ans+=max(abs(a[i-1]-a[i+1]),max(p[i-1],q[i+1]));        cout<<ans<<endl;    }    return 0;}

  


 

C.NanoApe Loves Sequence Ⅱ

Sol

枚举左端点,做尺取法就可以了.

Code

#include<cstdio>#include<iostream>using namespace std;int p[200005];int n,m,k;int T,x;long long ans;int main(){    int i,j;    scanf("%d",&T);    while(T--){        ans=0;        scanf("%d%d%d",&n,&m,&k);        for(i=1;i<=n;i++){            scanf("%d",&x);            if(x>=m) p[i]=1+p[i-1];            else p[i]=p[i-1];        }        for(i=1,j=1;i<=n;i++){            for(;p[j]-p[i-1]<k&&j<=n;j++);            ans+=n-j+1;        }cout<<ans<<endl;    }return 0;}

  


D.Keep In Touch

Sol

DAG上的DP.

注意输入的时候 \(u<v\) 这就保证了是一个有向无环图,我当时没注意,一直在想有环怎么做.

\(f[i][j][k]\) 表示第1个人第2个人第3个人的位置分别为 \(\i) , \(j\) ,\(k\) 的方案数.

然后直接DP是 \(O(n^6)\) ,加一维表示当前考虑到了第 \(p\) 个人.

注意转移的时候只需要判断第1个人是否合法就可以了,因为第2.3个人还没有走到相应的位置.

Code

#include<cstdio>#include<cstring>#include<vector>#include<iostream>using namespace std;typedef long long LL;const int N = 55;const LL Mo = 998244353;int T,n,m,K,q;int w[N];LL f[N][N][N][4];vector<int> g[N];inline int in(int x=0,char ch=getchar()){ while(ch>‘9‘||ch<‘0‘) ch=getchar();	while(ch>=‘0‘&&ch<=‘9‘) x=(x<<3)+(x<<1)+ch-‘0‘,ch=getchar();return x; }inline int abs(int x){ return x<0?-x:x; }inline int check(int a,int b,int c){	if(abs(w[a]-w[b])>K||abs(w[a]-w[c])>K||abs(w[b]-w[c])>K) return 0;	return 1;}int main(){//	freopen("in.in","r",stdin);	for(T=in();T--;){		memset(f,0,sizeof(f));for(int i=0;i<N;i++) g[i].clear();		n=in(),m=in(),K=in(),q=in();		for(int i=1;i<=n;i++) w[i]=in();				for(int i=1,u,v;i<=m;i++) u=in(),v=in(),g[u].push_back(v);				for(int i=n;i;i--) for(int j=n;j;j--) for(int k=n;k;k--){			f[i][j][k][1]=1;			for(int p=0;p<g[i].size();p++) f[i][j][k][1]=(f[i][j][k][1]+f[g[i][p]][j][k][3])%Mo;			for(int p=0;p<g[j].size();p++) f[i][j][k][2]=(f[i][j][k][2]+f[i][g[j][p]][k][1])%Mo;			for(int p=0;p<g[k].size();p++) f[i][j][k][3]=(f[i][j][k][3]+f[i][j][g[k][p]][2])%Mo;			if(!check(i,j,k)) f[i][j][k][1]=0;		}		//		for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) for(int k=1;k<=n;k++)//			cout<<i<<" "<<j<<" "<<k<<"-->"<<f[i][j][k][1]<<" "<<f[i][j][k][2]<<" "<<f[i][j][k][3]<<endl;				for(int i=1,x,y,z;i<=q;i++){			x=in(),y=in(),z=in();			printf("%I64d\n",f[x][y][z][1]);		}	}return 0;}

  


E.Price List Strike Back

Sol

考虑对序列的分治,

\(Solve(l,r,L,R)\) 表示处理左右端点在 \([l,r]\) 中的问题 \([L,R]\) .

分三种情况 \(r_i<=mid\) \(l_i>mid\) \(l_i<=mid<r_i\)

对于前两种情况我们扔到 \(Solve(l,mid)\) 和 \(Solve(mid+1,r)\) 中处理.

跨过中间点 \(mid\) 的方案数可以用背包在 \(O(100(r-l+1))\) 的时间内处理出来.

\(f[i][j]\) 表示从 \(i\) 到 \(mid\) 得到 \(j\) 的最长的最短距离.

\(g[i][j]\) 表示从 \(mid+1\) 到 \(i\) 得到 \(j\) 的最长的最短距离.

然后统计就是

\(c_i=min(c_i,max(f[l_i][j],g[r_i][s_i-j]\)

复杂度 \(O(nlogn+m)\)

PS:数组开小 T掉了...

Code

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>using namespace std;const int N = 20005;const int QM = 100005;const int M = 105;const int INF = 0x7f7f7f7f;#define mid ((l+r)>>1)#define lc (o<<1)#define rc (o<<1|1)#define debug(a) cout<<#a<<"="<<a<<" "int T,n,m;int w[N],d[N];struct Q{ int l,r,s,c,id; }q[QM],tmp[QM];bool operator < (const Q &a,const Q &b){ return a.id<b.id; }int f[N][M],g[N][M];int ans[QM];inline int in(int x=0,char ch=getchar()){ while(ch>‘9‘||ch<‘0‘) ch=getchar();	while(ch>=‘0‘&&ch<=‘9‘) x=(x<<3)+(x<<1)+ch-‘0‘,ch=getchar();return x; }void Solve(int l,int r,int L,int R){	if(L>R) return;	if(l==r){		if(L<=R) for(int i=L;i<=R;i++) ans[q[i].id]=(w[l]!=q[i].s||d[l]>q[i].c)?1:0;		return;    }	int h1=L;	for(int i=L;i<=R;i++) if(q[i].r<=mid) tmp[h1++]=q[i];	int h2=h1;	for(int i=L;i<=R;i++) if(q[i].l<=mid&&q[i].r>mid) tmp[h2++]=q[i];	int h3=h2;	for(int i=L;i<=R;i++) if(q[i].l>mid) tmp[h3++]=q[i];		for(int i=L;i<=R;i++) q[i]=tmp[i];		Solve(l,mid,L,h1-1),Solve(mid+1,r,h2,h3-1);		if(h2-h1<=0) return;	memset(f[mid],0x7f,sizeof(f[mid]));f[mid][w[mid]]=d[mid],f[mid][0]=0;    for(int i=mid-1;i>=l;i--) for(int j=100;~j;j--){		f[i][j]=f[i+1][j];		if(j>=w[i]&&f[i+1][j-w[i]]<INF) f[i][j]=min(f[i][j],max(f[i+1][j-w[i]],d[i]));	}		memset(g[mid+1],0x7f,sizeof(g[mid+1]));g[mid+1][w[mid+1]]=d[mid+1],g[mid+1][0]=0;	for(int i=mid+2;i<=r;i++) for(int j=100;~j;j--){		g[i][j]=g[i-1][j];		if(j>=w[i]&&g[i-1][j-w[i]]<INF) g[i][j]=min(g[i][j],max(g[i-1][j-w[i]],d[i]));	}    	for(int i=h1;i<h2;i++){		for(int j=0;j<=q[i].s;j++) ans[q[i].id]=min(ans[q[i].id],max(f[q[i].l][j],g[q[i].r][q[i].s-j]));		if(ans[q[i].id]>q[i].c) ans[q[i].id]=1;else ans[q[i].id]=0;	}}int main(){//	freopen("in.in","r",stdin);//	freopen("out.out","w",stdout);	for(T=in();T--;){		n=in(),m=in();		for(int i=1;i<=n;i++) w[i]=in();for(int i=1;i<=n;i++) d[i]=in();		for(int i=1;i<=m;i++) q[i].l=in(),q[i].r=in(),q[i].c=in(),q[i].s=in(),q[i].id=i,ans[i]=INF;		Solve(1,n,1,m);		for(int i=1;i<=m;i++) putchar(ans[i]+‘0‘);putchar(‘\n‘);	}return 0;}

  

 

BestCoder Round #86 解题报告