Codeforces Round #660 Div. 2 题解

A

最小的四个近似素数 6 , 10 , 14 , 15 6,10,14,15 6,10,14,15,容易发现,当 n ≤ 30 n\leq 30 n30 时,是一定无解的,因为最小的三个近似素数加起来就有 30 30 30

否则的话,我们一定可以用 6 , 10 , 14 , n − 30 6,10,14,n-30 6,10,14,n30 6 , 10 , 15 , n − 31 6,10,15,n-31 6,10,15,n31 来表示出 n n n,因为当第一种方式表示不出来时,一定满足 n − 30 n-30 n30 等于 6 , 10 , 14 6,10,14 6,10,14 中的一个,那么 n − 31 n-31 n31 就不可能等于 6 , 10 , 15 6,10,15 6,10,15 中的任何一个。

代码如下:

#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;

namespace my
{
	//-----------------------------------------------------------------------------
	inline char cn()
	{
		static char buf[1000010],*p1=buf,*p2=buf;
		return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
	}
	#define cn getchar
	template<class TY>void read(TY &x)
	{
		x=0;int f1=1;char ch=cn();
		while(ch<'0'||ch>'9'){if(ch=='-')f1=-1;ch=cn();}
		while(ch>='0'&&ch<='9')x=x*10+(ch-'0'),ch=cn(); x*=f1;
	}
	char Output[1000100],Zk[100];int op_top=0,Zk_top;
	void fcheck(int Type=0){if(Type||op_top>=1000000)fwrite(Output,1,op_top,stdout),op_top=0;}
	template<class TY>inline void write(TY x)
	{
		if(x==0){Output[op_top++]='0';fcheck();return;}
		Zk_top=0;while(x)Zk[++Zk_top]=x%10+'0',x/=10;
		while(Zk_top)Output[op_top++]=Zk[Zk_top--];fcheck();
	}
	#define K_G Output[op_top++]=' '
	#define H_C Output[op_top++]='\n'
	//--------------------------------------------------------------------------------------------
	
	//--------------------------------------------------------------------------------------------
	#define ll long long
	#define uint unsigned int
	#define ull unsigned long long
	#define INV(x) ksm(x,mod-2)
	#define inf 999999999
	#define mod 998244353
	
	template<class TY>void add(TY &x,TY y){x=(x+y>=mod?x+y-mod:x+y);}
	template<class TY>void dec(TY &x,TY y){x=(x-y<0?x-y+mod:x-y);}
	template<class TY>TY add(TY x){return x>=mod?x-mod:x;}
	template<class TY>TY dec(TY x){return x<0?x+mod:0;}
	//
	int ksm(int x,int y){int re=1;for(;(y&1?re=1ll*re*x%mod:0),y;y>>=1,x=1ll*x*x%mod);return re;}
	int *fac,*inv_fac,*inv;
	void work_math(const int N)
	{
		fac=new int[N+5];inv_fac=new int[N+5];inv=new int[N+5];
		inv[1]=1;for(int i=2;i<=N;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
		fac[0]=inv_fac[0]=1;for(int i=1;i<=N;i++)fac[i]=1ll*fac[i-1]*i%mod;
		inv_fac[N]=INV(fac[N]);
		for(int i=N-1;i>=1;i--)inv_fac[i]=1ll*inv_fac[i+1]*(i+1)%mod;
	}
	int C(int x,int y){return 1ll*fac[x]*inv_fac[y]%mod*inv_fac[x-y]%mod;}
	//
	template<class TY>TY gcd(TY x,TY y){return !y?x:gcd(y,x%y);}
	template<class TY>TY exgcd(TY a,TY b,TY &x,TY &y){
		if(!b)return x=1,y=0,a;
		TY re=exgcd(b,a%b,y,x);
		return y-=a/b*x,re;
	}
	//
	template<class TY>void discretization(TY *arr,int St,int Ed){
		vector<TY>Arr;Arr.clear();
		for(int i=St;i<=Ed;i++)Arr.push_back(arr[i]);
		sort(Arr.begin(),Arr.end());
		for(int i=St;i<=Ed;i++)arr[i]=lower_bound(Arr.begin(),Arr.end(),arr[i])-Arr.begin()+1;
	}
	//-----------------------------------------------------------------------------------------------
	
	//----------------------------------------------------------------------------------------------- 
	int T,n;
	
	void main()
	{
		read(T);while(T--)
		{
			read(n);//6 10 14
			if(n>30){
				printf("YES\n");
				if(n-30!=6&&n-30!=10&&n-30!=14)printf("6 10 14 %d\n",n-30);
				else printf("6 10 15 %d\n",n-31);
			}else printf("NO\n");
		}
		fcheck(1);return;
	}
}

int main(){my::main();return 0;}

B

仔细思考,可以发现答案一定是若干个 9 9 9 加若干个 8 8 8,前面的 9 9 9 是为了让 r r r 最大, 8 8 8 是为了在 k k k 最小的前提下提供尽可能多的二进制位,这样删掉后 n n n 位后可以让 r r r 的位数最多。

代码如下:

#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;

namespace my
{
	//-----------------------------------------------------------------------------
	inline char cn()
	{
		static char buf[1000010],*p1=buf,*p2=buf;
		return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
	}
	#define cn getchar
	template<class TY>void read(TY &x)
	{
		x=0;int f1=1;char ch=cn();
		while(ch<'0'||ch>'9'){if(ch=='-')f1=-1;ch=cn();}
		while(ch>='0'&&ch<='9')x=x*10+(ch-'0'),ch=cn(); x*=f1;
	}
	char Output[1000100],Zk[100];int op_top=0,Zk_top;
	void fcheck(int Type=0){if(Type||op_top>=1000000)fwrite(Output,1,op_top,stdout),op_top=0;}
	template<class TY>inline void write(TY x)
	{
		if(x==0){Output[op_top++]='0';fcheck();return;}
		Zk_top=0;while(x)Zk[++Zk_top]=x%10+'0',x/=10;
		while(Zk_top)Output[op_top++]=Zk[Zk_top--];fcheck();
	}
	#define K_G Output[op_top++]=' '
	#define H_C Output[op_top++]='\n'
	//--------------------------------------------------------------------------------------------
	
	//--------------------------------------------------------------------------------------------
	#define ll long long
	#define uint unsigned int
	#define ull unsigned long long
	#define INV(x) ksm(x,mod-2)
	#define inf 999999999
	#define mod 998244353
	
	template<class TY>void add(TY &x,TY y){x=(x+y>=mod?x+y-mod:x+y);}
	template<class TY>void dec(TY &x,TY y){x=(x-y<0?x-y+mod:x-y);}
	template<class TY>TY add(TY x){return x>=mod?x-mod:x;}
	template<class TY>TY dec(TY x){return x<0?x+mod:0;}
	//
	int ksm(int x,int y){int re=1;for(;(y&1?re=1ll*re*x%mod:0),y;y>>=1,x=1ll*x*x%mod);return re;}
	int *fac,*inv_fac,*inv;
	void work_math(const int N)
	{
		fac=new int[N+5];inv_fac=new int[N+5];inv=new int[N+5];
		inv[1]=1;for(int i=2;i<=N;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
		fac[0]=inv_fac[0]=1;for(int i=1;i<=N;i++)fac[i]=1ll*fac[i-1]*i%mod;
		inv_fac[N]=INV(fac[N]);
		for(int i=N-1;i>=1;i--)inv_fac[i]=1ll*inv_fac[i+1]*(i+1)%mod;
	}
	int C(int x,int y){return 1ll*fac[x]*inv_fac[y]%mod*inv_fac[x-y]%mod;}
	//
	template<class TY>TY gcd(TY x,TY y){return !y?x:gcd(y,x%y);}
	template<class TY>TY exgcd(TY a,TY b,TY &x,TY &y){
		if(!b)return x=1,y=0,a;
		TY re=exgcd(b,a%b,y,x);
		return y-=a/b*x,re;
	}
	//
	template<class TY>void discretization(TY *arr,int St,int Ed){
		vector<TY>Arr;Arr.clear();
		for(int i=St;i<=Ed;i++)Arr.push_back(arr[i]);
		sort(Arr.begin(),Arr.end());
		for(int i=St;i<=Ed;i++)arr[i]=lower_bound(Arr.begin(),Arr.end(),arr[i])-Arr.begin()+1;
	}
	//-----------------------------------------------------------------------------------------------
	
	//----------------------------------------------------------------------------------------------- 
	int T,n;
	
	void main()
	{
		read(T);while(T--)
		{
			read(n);
			int a=n/4,b=(n%4>0);
			for(int i=1;i<=n-a-b;i++)write(9);
			for(int i=1;i<=a+b;i++)write(8);
		}
		fcheck(1);return;
	}
}

int main(){my::main();return 0;}

C

人从树根往每个点走,在路上可能心情由好变不好,转化一下就是:人从每个点往根走,在路上可能心情由不好变好。

假设 x x x 子树内的所有人心情都是好的,那么可以得到该点的心情指数的上限,而将所有儿子的 h h h 加起来,再加上 − p [ x ] -p[x] p[x],则可以得到心情指数的下限,我们需要判断 h [ x ] h[x] h[x] 是否在这个上下限内。

如果一个人的心情由坏变好,那么心情指数会 + 2 +2 +2,所以需要判断 h [ x ] h[x] h[x] 到上下限的距离是否为偶数。

但凡有一个人不满足上面一个要求,那么答案就是NO了,代码如下:

#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;

namespace my
{
	//-----------------------------------------------------------------------------
	inline char cn()
	{
		static char buf[1000010],*p1=buf,*p2=buf;
		return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
	}
	#define cn getchar
	template<class TY>void read(TY &x)
	{
		x=0;int f1=1;char ch=cn();
		while(ch<'0'||ch>'9'){if(ch=='-')f1=-1;ch=cn();}
		while(ch>='0'&&ch<='9')x=x*10+(ch-'0'),ch=cn(); x*=f1;
	}
	char Output[1000100],Zk[100];int op_top=0,Zk_top;
	void fcheck(int Type=0){if(Type||op_top>=1000000)fwrite(Output,1,op_top,stdout),op_top=0;}
	template<class TY>inline void write(TY x)
	{
		if(x==0){Output[op_top++]='0';fcheck();return;}
		Zk_top=0;while(x)Zk[++Zk_top]=x%10+'0',x/=10;
		while(Zk_top)Output[op_top++]=Zk[Zk_top--];fcheck();
	}
	#define K_G Output[op_top++]=' '
	#define H_C Output[op_top++]='\n'
	//--------------------------------------------------------------------------------------------
	
	//--------------------------------------------------------------------------------------------
	#define ll long long
	#define uint unsigned int
	#define ull unsigned long long
	#define INV(x) ksm(x,mod-2)
	#define inf 999999999
	#define mod 998244353
	
	template<class TY>void add(TY &x,TY y){x=(x+y>=mod?x+y-mod:x+y);}
	template<class TY>void dec(TY &x,TY y){x=(x-y<0?x-y+mod:x-y);}
	template<class TY>TY add(TY x){return x>=mod?x-mod:x;}
	template<class TY>TY dec(TY x){return x<0?x+mod:0;}
	//
	int ksm(int x,int y){int re=1;for(;(y&1?re=1ll*re*x%mod:0),y;y>>=1,x=1ll*x*x%mod);return re;}
	int *fac,*inv_fac,*inv;
	void work_math(const int N)
	{
		fac=new int[N+5];inv_fac=new int[N+5];inv=new int[N+5];
		inv[1]=1;for(int i=2;i<=N;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
		fac[0]=inv_fac[0]=1;for(int i=1;i<=N;i++)fac[i]=1ll*fac[i-1]*i%mod;
		inv_fac[N]=INV(fac[N]);
		for(int i=N-1;i>=1;i--)inv_fac[i]=1ll*inv_fac[i+1]*(i+1)%mod;
	}
	int C(int x,int y){return 1ll*fac[x]*inv_fac[y]%mod*inv_fac[x-y]%mod;}
	//
	template<class TY>TY gcd(TY x,TY y){return !y?x:gcd(y,x%y);}
	template<class TY>TY exgcd(TY a,TY b,TY &x,TY &y){
		if(!b)return x=1,y=0,a;
		TY re=exgcd(b,a%b,y,x);
		return y-=a/b*x,re;
	}
	//
	template<class TY>void discretization(TY *arr,int St,int Ed){
		vector<TY>Arr;Arr.clear();
		for(int i=St;i<=Ed;i++)Arr.push_back(arr[i]);
		sort(Arr.begin(),Arr.end());
		for(int i=St;i<=Ed;i++)arr[i]=lower_bound(Arr.begin(),Arr.end(),arr[i])-Arr.begin()+1;
	}
	//-----------------------------------------------------------------------------------------------
	
	//----------------------------------------------------------------------------------------------- 
	#define maxn 100010
	int T,n,m;
	struct edge{int y,next;}e[maxn<<1];
	int first[maxn],len=0;
	void buildroad(int x,int y){e[++len]=(edge){y,first[x]};first[x]=len;}
	ll a[maxn],h[maxn],size[maxn];
	bool ans;
	void dfs(int x,int fa){
		ll tot=-a[x];
		for(int i=first[x];i;i=e[i].next){
			int y=e[i].y;if(y==fa)continue;
			dfs(y,x);tot+=h[y];a[x]+=a[y];
		}
		bool v1=(tot%2!=0),v2=(a[x]%2!=0);
		if(v1!=v2)ans=false;//这一句可能是多余的,总之写上比较保险
		if(h[x]<tot||h[x]>a[x])ans=false;
		if((h[x]-tot)%2)ans=false;
	}
	
	void main()
	{
		read(T);while(T--)
		{
			read(n);read(m);
			for(int i=1;i<=n;i++)read(a[i]);
			for(int i=1;i<=n;i++)read(h[i]);
			memset(first,0,(n+1)<<2);len=0;
			for(int i=1,x,y;i<n;i++)read(x),read(y),
			buildroad(x,y),buildroad(y,x);
			ans=true;dfs(1,0);
			if(ans)printf("YES\n");
			else printf("NO\n");
		}
		fcheck(1);return;
	}
}

int main(){my::main();return 0;}

T4

可以发现所有位置构成了一个森林的结构,那么我们只需要确定每对父子间的操作顺序,就可以得到总的操作顺序了。

要使得答案尽可能大,那么可以考虑贪心,设 f [ x ] f[x] f[x] 表示 x x x 位置能达到的最大值,那么它的父亲在考虑 x x x 时,假如 f [ x ] f[x] f[x] 大于 0 0 0,那么肯定先操作 x x x,再操作 x x x 的父亲。

将这些操作顺序造成图, x → y x\to y xy 这条边表示 x x x 的操作顺序在 y y y 之前,然后求一下这张图的拓扑序即可。

代码如下:

#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;

namespace my
{
	//-----------------------------------------------------------------------------
	inline char cn()
	{
		static char buf[1000010],*p1=buf,*p2=buf;
		return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
	}
	#define cn getchar
	template<class TY>void read(TY &x)
	{
		x=0;int f1=1;char ch=cn();
		while(ch<'0'||ch>'9'){if(ch=='-')f1=-1;ch=cn();}
		while(ch>='0'&&ch<='9')x=x*10+(ch-'0'),ch=cn(); x*=f1;
	}
	char Output[1000100],Zk[100];int op_top=0,Zk_top;
	void fcheck(int Type=0){if(Type||op_top>=1000000)fwrite(Output,1,op_top,stdout),op_top=0;}
	template<class TY>inline void write(TY x)
	{
		if(x==0){Output[op_top++]='0';fcheck();return;}
		if(x<0)Output[op_top++]='-',x=-x;
		Zk_top=0;while(x)Zk[++Zk_top]=x%10+'0',x/=10;
		while(Zk_top)Output[op_top++]=Zk[Zk_top--];fcheck();
	}
	#define K_G Output[op_top++]=' '
	#define H_C Output[op_top++]='\n'
	//--------------------------------------------------------------------------------------------
	
	//--------------------------------------------------------------------------------------------
	#define ll long long
	#define uint unsigned int
	#define ull unsigned long long
	#define INV(x) ksm(x,mod-2)
	#define inf 999999999
	#define mod 998244353
	
	template<class TY>void add(TY &x,TY y){x=(x+y>=mod?x+y-mod:x+y);}
	template<class TY>void dec(TY &x,TY y){x=(x-y<0?x-y+mod:x-y);}
	template<class TY>TY add(TY x){return x>=mod?x-mod:x;}
	template<class TY>TY dec(TY x){return x<0?x+mod:0;}
	//
	int ksm(int x,int y){int re=1;for(;(y&1?re=1ll*re*x%mod:0),y;y>>=1,x=1ll*x*x%mod);return re;}
	int *fac,*inv_fac,*inv;
	void work_math(const int N)
	{
		fac=new int[N+5];inv_fac=new int[N+5];inv=new int[N+5];
		inv[1]=1;for(int i=2;i<=N;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
		fac[0]=inv_fac[0]=1;for(int i=1;i<=N;i++)fac[i]=1ll*fac[i-1]*i%mod;
		inv_fac[N]=INV(fac[N]);
		for(int i=N-1;i>=1;i--)inv_fac[i]=1ll*inv_fac[i+1]*(i+1)%mod;
	}
	int C(int x,int y){return 1ll*fac[x]*inv_fac[y]%mod*inv_fac[x-y]%mod;}
	//
	template<class TY>TY gcd(TY x,TY y){return !y?x:gcd(y,x%y);}
	template<class TY>TY exgcd(TY a,TY b,TY &x,TY &y){
		if(!b)return x=1,y=0,a;
		TY re=exgcd(b,a%b,y,x);
		return y-=a/b*x,re;
	}
	//
	template<class TY>void discretization(TY *arr,int St,int Ed){
		vector<TY>Arr;Arr.clear();
		for(int i=St;i<=Ed;i++)Arr.push_back(arr[i]);
		sort(Arr.begin(),Arr.end());
		for(int i=St;i<=Ed;i++)arr[i]=lower_bound(Arr.begin(),Arr.end(),arr[i])-Arr.begin()+1;
	}
	//-----------------------------------------------------------------------------------------------
	
	//----------------------------------------------------------------------------------------------- 
	#define maxn 200010
	int n,du[maxn];
	ll val[maxn],ans=0;
	struct edge{int y,next;}e[maxn<<1];
	int first[maxn],len=0;
	void buildroad(int x,int y){e[++len]=(edge){y,first[x]};first[x]=len;}
	vector<int>st,to[maxn];
	void dfs(int x){
		for(int i=first[x];i;i=e[i].next){
			int y=e[i].y;dfs(y);
			if(val[y]>0)val[x]+=val[y],to[y].push_back(x),du[x]++;
			else to[x].push_back(y),du[y]++;
		}
		ans+=val[x];
	}
	int zhan[maxn],t=0;
	
	void main()
	{
		read(n);st.clear();
		for(int i=1;i<=n;i++)read(val[i]);
		for(int i=1,fa;i<=n;i++){
			read(fa);to[i].clear();
			if(fa==-1)st.push_back(i);
			else buildroad(fa,i);
		}
		for(int i=0;i<st.size();i++)dfs(st[i]);
		write(ans);H_C;
		for(int i=1;i<=n;i++)if(!du[i])zhan[++t]=i;
		while(t){
			int x=zhan[t--];
			write(x);K_G;
			for(int i=0;i<to[x].size();i++){
				du[to[x][i]]--;
				if(!du[to[x][i]])zhan[++t]=to[x][i];
			}
		}
		fcheck(1);return;
	}
}

int main(){my::main();return 0;}

E

做法是膜的洛谷里的题解qwq。

先将整个平面沿着 y = x y=x y=x 这条直线翻转,这样就避免了斜率不存在的情况。

一开始自己的想法是直接三分斜率,因为令 f ( k ) f(k) f(k) 表示斜率为 k k k 时的答案,那么 f ( x ) f(x) f(x) 比较显然是个单谷函数,但是三分到不合法斜率时难以处理,有可能可行解夹在两个不合法斜率之间。

洛谷题解做法是,先枚举两两线段,它们之间存在一个不合法斜率区间,斜率如果取这个区间那么这两条线段会相交,将所有区间取并就是斜率的不合法取值范围。

有一个小结论,所有不合法区间取并之后,会得到若干个斜率区间,答案最优时,斜率一定取某个区间的端点。

证明很简单,因为当斜率变化时答案具有凸性,所以如果一个斜率 k k k 是可行解并且 k k k 不在某个区间的端点上,那么将 k k k f ( k ) f(k) f(k) 的谷的位置移动一定会使得答案更优,一直移动下去就撞到某个区间的端点上了。

所以只需要把所有区间的端点拿出来三分即可。

代码如下:

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define maxn 2010
#define eps 1e-10

int n;
struct segment{int l,r,x;}a[maxn];
struct par{double k;int id;};
vector<par>s;
vector<double>k;
bool cmp(par x,par y){return x.k==y.k?(x.id>y.id):x.k<y.k;}
double calc(double k_){
	double mi=1e18,ma=-1e18;
	for(int i=1;i<=n;i++)mi=min(mi,1.0*a[i].l-k_*a[i].x),ma=max(ma,1.0*a[i].r-k_*a[i].x);
	return ma-mi;
}

int main()
{
	scanf("%d",&n);s.clear();k.clear();
	for(int i=1;i<=n;i++)scanf("%d %d %d",&a[i].l,&a[i].r,&a[i].x);
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++)if(a[i].x!=a[j].x){
			double k1=1.0*(a[i].r-a[j].l)/(a[i].x-a[j].x);
			double k2=1.0*(a[i].l-a[j].r)/(a[i].x-a[j].x);
			if(k1>k2)swap(k1,k2);
			s.push_back((par){k1+eps,-1});s.push_back((par){k2-eps,1});
		}
	}
	sort(s.begin(),s.end(),cmp);
	for(int i=0,tot=0;i<s.size();i++){
		if(s[i].id==-1&&tot==0)k.push_back(s[i].k);
		if(s[i].id==1&&tot==-1)k.push_back(s[i].k);
		tot+=s[i].id;
	}
	if(!k.size())return printf("%.8lf",calc(0)),0;
	int l=0,r=k.size()-1,mid1,mid2;
	while(r-l>2){
		mid1=l+(r-l+1)/3;
		mid2=mid1+(r-l+1)/3;
		if(calc(k[mid1])-calc(k[mid2])>eps)l=mid1+1;
		else r=mid2-1;
	}
	double ans=calc(k[l]);
	for(int i=l+1;i<=r;i++)ans=min(ans,calc(k[i]));
	printf("%.8lf",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值