把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

Codeforces Round #701 (Div. 2)

CF1485A
很不寻常的A题。
首先肯定有结论:第二个操作先做,再做第一个操作最优。
然后可以发现,操作次数不会超过一个很小的数。
所以可以枚举第二个操作的次数。然后计算即可。
这里取\(w=40\)
时间复杂度\(O(Tlog^2n)\)
code:

#include<cstdio>
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,m,k,x,y,z,t,ans,tot,now;
int main(){
	register int i;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);ans=1e9;
		for(i=0;i<=40;i++){
			tot=i;
			now=n;
			if(!i&&m==1) continue;
			while(now) now/=m+i,tot++;
			ans=min(ans,tot);
		}
		printf("%d\n",ans);
	}
}

CF1485B
因为只能有一个位置不同考虑枚举这个不同的位置。
显然这个不同的位置\(i\)的方案数是\(a_{i+1}-a_{i-1}-1\)
然而要特别注意一下第一个和最后一个,第一个的下界是\(1\),最后一个上界是\(k\)
然后前缀和一下即可。
code:

#include<cstdio>
using namespace std;
long long n,m,k,x,y,z,a[100039],q[100039];
int main(){
	register int i;
	scanf("%lld%lld%lld",&n,&m,&k);
	for(i=1;i<=n;i++) scanf("%lld",&a[i]);
	for(i=2;i<n;i++) q[i]=a[i+1]-a[i-1]-2,q[i]+=q[i-1];
	for(i=1;i<=m;i++){
		scanf("%lld%lld",&x,&y);
		if(x==y) printf("%lld\n",k-1);
		else{
			printf("%lld\n",a[x+1]-2+q[y-1]-q[x]+k-a[y-1]-1);
		}
	}
}

CF1485C
\(⌊\frac{a}{b}⌋=a \bmod b=k\)
然后发现\(a=k(b+1)\)
所以对于一个\(b\)的取值\(i\),这里的答案为\(⌊\frac{a}{i+1}⌋\)
然而因为余数不能大于除数。
所以这个答案要与\(i-1\)\(\min\)
发现这部分单独处理的部分不会超过\(\sqrt n\),所以可以先求出上面一部分的答案,然后对于这一部分重新算。
上一部分套整除分块板子即可。
时间复杂度\(O(T\sqrt b)\)
code:

#include<cstdio>
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
long long n,m,k,x,y,z,T,ans,tot,pus;
inline long long h(long long x,long long m){
	long long res=0,j;long long i,now;
	for(i=1;i<=min(x+1,m);i=j+1){
		j=m/(m/i);
		res+=(j-i+1)*(m/i);now=m/i;
	}res-=m;
	if(i>x+1) res-=now*(i-x-2);
	for(i=1;i*i<=m&&i<=x;i++){
		res-=m/(i+1);
		res+=i-1;
	}
	return res;
}
int main(){
//	freopen("1.in","r",stdin);
	register int i;
	scanf("%d",&T);
	while(T--){
		scanf("%lld%lld",&x,&y);
		printf("%lld\n",h(y,x));
	}

CF1485D
可以发现\(a_{i,j}\)很小,所以从这里入手。
对于每个\(b_{i,j}\),我们使它为\(720720\),这是\(1\)\(16\)所有数的最小公倍数。
但是这样没法完成相邻差为\(k^4\)的任务。
考虑将矩阵黑白染色,然后对于白块的\(b_{i,j}\)加上\(a_{i,j}^4\)即可。
code:

#include<cstdio>
using namespace std;
int n,m,k,x,y,z,a[539][539],b[530][539];
int main(){
	register int i,j;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++) scanf("%d",&a[i][j]);
	}
	for(i=1;i<=n;i++){
		for(j=(i&1)+1;j<=m;j+=2) b[i][j]=a[i][j]*a[i][j]*a[i][j]*a[i][j];
	}
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++) printf("%d ",b[i][j]+720720);printf("\n");
	}
}

CF1485E
这种东西就可以逐层处理。
然后设\(dp_{i}\)表示红球在\(i\)点时的最大收益。
有两种转移渠道:由父节点直接转移,由非父节点下方到儿子且蓝球在当前节点之后交换得来。
父节点直接转移是\(O(1)\)的,但是非父节点转移是\(O(n)\)的。
考虑这个怎么处理。
首先套路离散\(a_i\)且拆掉绝对值,这样分类处理。
接着发现就可以开两颗线段树处理了。一棵线段树表示小于当前节点权值的转移,另一棵表示大于的。
这个树状数组似乎也可以。
时间复杂度\(O(nlogn)\),代码难度略大。
code:

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define CI const int &
#define ll long long
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int n,m,k,x,y,z,t,a[200039],d[200039],nows[200039],tots[200039],ys[200039],l,r,mid,now,minn,maxn;
ll ans,dp[200039];
struct yyy{int to,z;}tmp;
struct ljb{
	int head,h[200039];yyy f[200039];
	inline void add(int x,int y){f[++head]=(yyy){y,h[x]};h[x]=head;}
}s;
vector<int> g[200039];
struct tree{
	ll sum[800039];
	inline void clear(int x,int y,CI l=1,CI r=n,CI now=1){
	    if(x<=l&&r<=y){sum[now]=-1e18;return;}
	    int m=l+r>>1;
	    if(x<=m) clear(x,y,l,m,now<<1);
     	if(y>m) clear(x,y,m+1,r,now<<1|1);
     }
     inline ll find(int x,CI l=1,CI r=n,CI now=1){
     	if(l==r)return sum[now];
		 int m=l+r>>1;ll fs=-1e18;
		 if(x<=m) fs=find(x,l,m,now<<1);
		 else fs=find(x,m+1,r,now<<1|1);
		 return max(fs,sum[now]); 
     }
     inline void get(int x,int y,ll z,CI l=1,CI r=n,CI now=1){
     	if(x<=l&&r<=y) {sum[now]=max(sum[now],z);return;}
     	int m=l+r>>1;
     	if(x<=m) get(x,y,z,l,m,now<<1);
     	if(y>m) get(x,y,z,m+1,r,now<<1|1);
     }
}f1,f2;
inline void dfs(int x){
	yyy tmp;
	for(int cur=s.h[x];cur;cur=tmp.z){
		tmp=s.f[cur];
		d[tmp.to]=d[x]+1;dfs(tmp.to);
	}
}
int main(){
	freopen("1.in","r",stdin);
	register int i,j;
	scanf("%d",&t);memset(f1.sum,-0x3f,sizeof(f1.sum));memset(f2.sum,-0x3f,sizeof(f2.sum));
	while(t--){
		for(i=1;i<=n;i++) dp[i]=d[i]=s.h[i]=0,g[i].clear();s.head=0;ans=0;g[0].clear();
		for(i=1;i<=4*n;i++) f1.sum[i]=f2.sum[i]=-1e18;
		scanf("%d",&n);
		for(i=2;i<=n;i++) scanf("%d",&x),s.add(x,i);
		for(i=2;i<=n;i++) scanf("%d",&a[i]),nows[i-1]=a[i];
		dfs(1);
		for(i=1;i<=n;i++)g[d[i]].push_back(i);
		sort(nows+1,nows+n);
		for(i=1;i<n;i++) tots[i]=(i^1)?(tots[i-1]+(nows[i]!=nows[i-1])):1,ys[tots[i]]=nows[i];
		for(i=2;i<=n;i++){
			l=0;r=n-1;
			while(l+1<r){
				mid=l+r>>1;
				if(nows[mid]<a[i]) l=mid;
				else r=mid;
			}
			a[i]=tots[r];
		}
		for(i=1;;i++){
			if(!g[i].size()) break;
			for(j=0;j<g[i-1].size();j++){
				now=g[i-1][j];yyy tmp;
				for(int cur=s.h[now];cur;cur=tmp.z){
					tmp=s.f[cur];
				    f1.get(1,a[tmp.to],dp[now]+ys[a[tmp.to]]);f2.get(a[tmp.to],n,dp[now]-ys[a[tmp.to]]);
				}
			}minn=1e9;maxn=-1e9;
			for(j=0;j<g[i].size();j++) now=g[i][j],dp[now]=max(f1.find(a[now])-ys[a[now]],f2.find(a[now])+ys[a[now]]);
			for(j=0;j<g[i].size();j++) now=g[i][j],minn=min(minn,ys[a[now]]),maxn=max(maxn,ys[a[now]]);
			for(j=0;j<g[i-1].size();j++){
				now=g[i-1][j];yyy tmp;
				for(int cur=s.h[now];cur;cur=tmp.z){
					tmp=s.f[cur];dp[tmp.to]=max(dp[tmp.to],dp[now]+max(maxn-ys[a[tmp.to]],ys[a[tmp.to]]-minn));
				}
			}
			for(j=0;j<g[i-1].size();j++){
				now=g[i-1][j];yyy tmp;
				for(int cur=s.h[now];cur;cur=tmp.z){
					tmp=s.f[cur];
				    f1.clear(1,a[tmp.to]);f2.clear(a[tmp.to],n);
				}
			}
		}
		for(i=1;i<=n;i++) ans=max(ans,dp[i]);
		printf("%lld\n",ans);
	}
}

CF1485F
咕咕咕

posted @ 2021-02-13 19:27  275307894a  阅读(78)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end