• 周四. 10 月 3rd, 2024

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

义乌集训7.14 contest 7题解

admin

11 月 28, 2021

2021.7.14 Contest 题解

T1:

Description:

​ 给定整数 (n),将 (1-n) 分成两组,每一组至少有一个数,并且使得两组数字的和的最大公约数最大,请输出最大的最大公约数。

Input:

​ 一行一个正整数 (n)

Output:

​ 一行一个整数,表示答案。

Sample1 Input:

6

Sample1 Output:

7

Hint:

(1< n<10^9)

题目分析:

​ 通过数学归纳法可知,给定 (1-n) 中的每一个数,则 ([1,n*(n+1)/2]) 都能用若干个数的和表示出来。

​ 于是原问题转化为求 (n*(n+1)/2) 的最大的和自己不相等的因数。直接把 (n)((n+1)) 分解质因数即可,稍微注意一些细节。

代码如下(马蜂很丑,不喜勿喷)——

#include<bits/stdc++.h>
#define LL long long
using namespace std;
int n,tmp1,tmp2;LL ans;inline int read(){int ret=0,f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-') f=-f;ch=getchar();}while(isdigit(ch)) ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();return ret*f;}
int main(){
	cin>>n,ans=1ll*n*(n+1)/2;if(n%4==0||(n+1)%4==0){cout<<ans/2ll<<'
';return 0;}
	for(register int i=3;i<=sqrt(n);i++) if(n%i==0){tmp1=i;break;} if(!tmp1) if(n%2==0) tmp1=n/2;else tmp1=n;
	for(register int i=3;i<=sqrt(n+1);i++) if((n+1)%i==0){tmp2=i;break;}if(!tmp2) if((n+1)%2==0) tmp2=(n+1)/2;else tmp2=n+1;
	int tmp=min(tmp1,tmp2);cout<<ans/(LL)tmp<<'
';return 0;
}

T2:

Description:

​ 在OI大陆,每个OIer都有一个rating。每场比赛以后,参赛者的rating都会发生改变。蜗蜗一共参加了 (n) 场比赛,所以他的rating一共变动了 (n) 次。在第场比赛后,他的rating变成了 (a_i)。我们不在意第 (1) 场比赛前他的rating是多少。

​ 佳佳是蜗蜗最好的朋友。蜗蜗想让佳佳对他的rating曲线有深刻的了解。每场比赛过后,蜗蜗都可以决定告诉或不告诉佳佳他最新的rating。如果蜗蜗决定告诉佳佳,佳佳会收到蜗蜗最新的rating,否则佳佳会假设蜗蜗的rating仍旧是上次告诉他的时候的样子。蜗蜗想要保证在任何时候,蜗蜗实际的rating和佳佳知道的蜗蜗的rating的差的绝对值不超过 (m)

​ 在第一场比赛过后,蜗蜗必须告诉佳佳他的rating。

​ 请问蜗蜗最少要告诉佳佳几次他的rating?

Input:

​ 第一行两个整数 (n,m)。 第二行 (n) 个整数 ({a_n})

Output:

​ 输出一行一个整数表示答案。

Sample1 Input:

4 0
1 2 2 3

Sample1 Output:

3

Sample2 Input:

6 5
6 5 0 10 0 10

Sample2 Output:

2

Hint:

对于 (20\%) 的数据,(1 le n le 20)

对于 (100\%) 的数据,(1 le n le 5 imes 10^3,0 le m,a_i le 10^9)

题目分析:

阅读理解DP入门题,直接设 (f_i) 表示到第 (i) 场比赛蜗蜗至少要告诉佳佳rating的次数。(O(n^2)) 转移即可,用线段树可以优化成 $ O(nlogn)$.

代码如下(马蜂很丑,不喜勿喷)——

#include<bits/stdc++.h>
#define N 5005
#define LL long long
using namespace std;
int n,m,a[N],f[N][2];struct FastIO{
	static const int S=1048576;
	char buf[S],*L,*R;int stk[20],Top;~FastIO(){clear();}
	inline char nc(){return L==R&&(R=(L=buf)+fread(buf,1,S,stdin),L==R)?EOF:*L++;}inline void clear(){fwrite(buf,1,Top,stdout);Top=0;}
	inline void pc(char ch){Top==S&&(clear(),0);buf[Top++]=ch;}inline void endl(){pc('
');}
	FastIO& operator >> (char&ch){while(ch=nc(),ch==' '||ch=='
');return *this;}
	template<typename T>FastIO& operator >> (T&ret){
		ret=0;int f=1;char ch=nc();while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=nc();}
		while(ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=nc();}ret*=f;return *this;
	}
	FastIO& operator >> (char* s){int Len=0;char ch=nc();while(ch!='
'){*(s+Len)=ch;Len++;ch=nc();}}
	template<typename T>FastIO& operator << (T x){
		if(x<0){pc('-');x=-x;}do{stk[++stk[0]]=x%10;x/=10;}while(x);
		while(stk[0]) pc('0'+stk[stk[0]--]);return *this;
	}
	FastIO& operator << (char ch){pc(ch);return *this;}
	FastIO& operator << (string str){int Len=str.size()-1;for(stk[0]=0;Len>=0;Len--) stk[++stk[0]]=str[Len];while(stk[0]) pc(stk[stk[0]--]);return *this;}
}fin,fout;
int main(){
	fin>>n>>m;for(register int i=1;i<=n;i++){fin>>a[i],f[i][0]=n,f[i][1]=min(f[i-1][0],f[i-1][1])+1;int Max=a[i],Min=a[i];for(register int j=i-1;j;j--){if(a[j]+m>=Max&&a[j]-m<=Min) f[i][0]=min(f[i][0],f[j][1]);Max=max(Max,a[j]),Min=min(Min,a[j]);}}cout<<min(f[n][0],f[n][1])<<'
';return 0;
}

T3:

Description:

对于 ([1,n]) 的子集 (A),它的分数 (s)

  1. 初始分数为 (0)
  2. 对于所有的 (i in A)(s+=a_i)
  3. 对于所有满足 (i,j in {x in A|x ge 2 },i^k=j(k in {x in Z|x ge 2})) 的二元组 ((i,j))(s-=b_j)

请求出分数最高的子集的分数是多少。

Input:

​ 第一行一个正整数 (n)

​ 第二行 (n) 个正整数 ({a_n})

​ 第三行 (n) 个正整数 ({b_n})

Output:

​ 一行一个数表示答案。

Sample1 Input:

4
1 1 1 2
1 1 1 1

Sample1 Output:

4

Sample2 Input:

4
1 1 1 1
1 1 1 2

Sample2 Output:

3

Hint:

对于 (20\%) 的数据,(n le 20)

对于全部数据,(1 leq n leq 10^5,1leq a_i,b_i leq 10^9.)

题目分析:

​ 对于某个质因数的幂次最多只会有 (16) 个数。爆搜即可。

代码如下(马蜂很丑,不喜勿喷)——

#include<bits/stdc++.h>
#define N 100005
#define LL long long
using namespace std;
int n,a[N],b[N],v[N];bool vis[N];LL res,ans;
inline void dfs(LL x,int y,LL s){if(x>n){res=max(res,s);return;} vis[x]=1;for(register LL i=1ll*x*x;i<=(LL)n;i*=x) v[i]++;dfs(x*y,y,s+max(0ll,(LL)a[x]-1ll*b[x]*v[x]));for(register LL i=1ll*x*x;i<=(LL)n;i*=x) v[i]--;dfs(x*y,y,s);}
struct FastIO{
	static const int S=1048576;
	char buf[S],*L,*R;int stk[20],Top;~FastIO(){clear();}
	inline char nc(){return L==R&&(R=(L=buf)+fread(buf,1,S,stdin),L==R)?EOF:*L++;}inline void clear(){fwrite(buf,1,Top,stdout);Top=0;}
	inline void pc(char ch){Top==S&&(clear(),0);buf[Top++]=ch;}inline void endl(){pc('
');}
	FastIO& operator >> (char&ch){while(ch=nc(),ch==' '||ch=='
');return *this;}
	template<typename T>FastIO& operator >> (T&ret){
		ret=0;int f=1;char ch=nc();while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=nc();}
		while(ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=nc();}ret*=f;return *this;
	}
	FastIO& operator >> (char* s){int Len=0;char ch=nc();while(ch!='
'){*(s+Len)=ch;Len++;ch=nc();}}
	template<typename T>FastIO& operator << (T x){
		if(x<0){pc('-');x=-x;}do{stk[++stk[0]]=x%10;x/=10;}while(x);
		while(stk[0]) pc('0'+stk[stk[0]--]);return *this;
	}
	FastIO& operator << (char ch){pc(ch);return *this;}
	FastIO& operator << (string str){int Len=str.size()-1;for(stk[0]=0;Len>=0;Len--) stk[++stk[0]]=str[Len];while(stk[0]) pc(stk[stk[0]--]);return *this;}
}fin,fout;
int main(){
//	freopen("set.in","r",stdin);freopen("set.out","w",stdout);
	fin>>n;for(register int i=1;i<=n;i++) fin>>a[i];for(register int i=1;i<=n;i++) fin>>b[i];ans=a[1];for(register int i=2;i<=n;i++) if(!vis[i]) res=0,dfs(i,i,0),ans+=res;cout<<ans<<'
';return 0;
}

T4:

Description:

​ mifafa 正在编写杭州城市大脑智能引擎。

​ 杭州的道路可以被抽象成为一幅无向图。每条路的初始速度都是 (1mathrm{m/s})

​ mifafa 可以使用 (1) ( exttt{RMB}) 让任意一条路的速度提升 (1mathrm{m/s})。如果一条路的速度为 (amathrm{m/s}),那么我们需要 (frac{1}{a}mathrm{s}) 才能通过这条道路。初始 mifafa 有 (k) ( exttt{RMB}),mifafa 要把这 (k) ( exttt{RMB}) 花在升级这些道路上。

​ 现在有两位选手,一位要从 (s_1) 走到 (t_1),一位要从 (s_{2333}) 走到 (t_{2333}),请问 mifafa 要怎么花钱,使得两位选手花费的总时间最少?当 mifafa 花完 ( exttt{RMB}) 之后,两位选手都会走花费时间最少的路。mifafa 花在每条道路上的钱都必须是非负整数。

Input:

​ 第一行三个整数 (n,m,k),表示点数,边数与初始 ( exttt{RMB}) 数。

​ 此后 (m) 行每行两个数表示边。

​ 此后一行四个整数表示 (s_1,t_1,s_{2333},t_{2333})。数据保证 (s_1,t_1)(s_{2333},t_{2333}) 联通

Output:

​ 一行一个数表示答案。相对误差或绝对误差在 ((frac{4^4-4^{frac{4}{4^{4-4}+4^{4-4}}}}{4 imes (4+4^{frac{4}{4+4}})})^{-4-4-4^{4-4}}) ((10^{-9})) 内即为正确。

Sample1 Input:

6 5 1
1 2
3 2
2 4
4 5
4 6
1 5 3 6

Sample1 Output:

5.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Sample2 Input:

1 0 100
1 1 1 1

Sample2 Output:

0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Sample3 Input:

4 2 3
1 2
3 4
1 2 3 4

Sample3 Output:

0.83333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333

Hint:

对于 (100\%) 的数据,满足 (0le n,mle 5 imes 10^3)(0le kle 10^9)

题目分析:

​ 先以每个点为起点跑一遍BFS。于是两条路径可以拆成形如 (s->x->y->t) 的柿子,其中 (x->y) 是两条路径的交。当然,两条路径不相交也可以。于是我们可以预处理出在相交的路径长度为 (i) 时剩余的最短路径 (A_i)

​ 我们枚举每个 (i),通过二分来确定分配 ( exttt{RMB}) 的方案。我们考虑到对于相交的路径会产生 (frac{2}{a}) 的贡献,而剩余的路径的贡献为 (frac{1}{a})。我们假设给每条相交的路径上的边分配 (x) ( exttt{RMB}) ,则给不相交的路径上的每条边分配的 ( exttt{RMB})(y) 满足 (frac{2}{x-1}-frac{2}{x} geq frac{1}{y}-frac{1}{y+1}),解出满足该方程的最大的 (y) ,判断给定的 (k) ( exttt{RMB}) 是否足够。如果足够,则 (x) 可能取到更大的值;反之,(x) 的值应当更小。

​ 二分出 (x) 之后计算即可。

代码如下(马蜂很丑,不喜勿喷)——

#include<bits/stdc++.h>
#define N 5005
#define inf 100000000
#define LL long long
#define DB double
using namespace std;
int n,m,K,s1,t1,s2,t2,H,T,tot,q[N],fir[N],nxt[N<<1],son[N<<1],dis[N][N],A[N];bool ok[N][N],vis[N];DB ans=inf;
inline void add(int x,int y){son[++tot]=y,nxt[tot]=fir[x],fir[x]=tot;} inline void bfs(int s){
	for(register int i=1;i<=n;i++) vis[i]=0,dis[s][i]=inf;vis[s]=1,H=T=1,dis[s][s]=0,q[1]=s;while(H<=T)
	{int x=q[H++];for(register int i=fir[x];i;i=nxt[i]) if(!vis[son[i]]) vis[son[i]]=1,q[++T]=son[i],dis[s][son[i]]=dis[s][x]+1;}
}
inline int read(){int ret=0,f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-') f=-f;ch=getchar();}while(isdigit(ch)) ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();return ret*f;}
int main(){
	n=read(),m=read(),K=read();for(register int i=1,x,y;i<=m;i++) x=read(),y=read(),(!ok[x][y])&&(add(x,y),add(y,x),ok[x][y]=ok[y][x]=1,0);A[0]=inf;for(register int i=1;i<=n;i++) A[i]=inf,bfs(i);s1=read(),t1=read(),s2=read(),t2=read();
	for(register int i=1;i<=n;i++) for(register int j=1;j<=n;j++){
		if((dis[s1][i]^inf)&&(dis[s2][i]^inf)&&(dis[t1][j]^inf)&&(dis[t2][j]^inf)&&(dis[i][j]^inf)) A[dis[i][j]]=min(A[dis[i][j]],dis[s1][i]+dis[s2][i]+dis[t1][j]+dis[t2][j]);
		if((dis[s1][i]^inf)&&(dis[s2][j]^inf)&&(dis[t1][j]^inf)&&(dis[t2][i]^inf)&&(dis[i][j]^inf)) A[dis[i][j]]=min(A[dis[i][j]],dis[s1][i]+dis[s2][j]+dis[t1][j]+dis[t2][i]);
	}
	A[0]=min(A[0],dis[s1][t1]+dis[s2][t2]);for(register int i=0;i<=n;i++){
		int x=i,y=A[i],l=1,r=K+1,xx=1;while(l<=r){
			int mid=l+r>>1;LL delta=4ll+8ll*mid*(mid-1),X=(LL)ceil((-2.0+sqrt(delta))/4.0);
			while(2ll*(X-1)*X>=1ll*mid*(mid-1)&&X>1) X--;LL res=1ll*(mid-1)*x+1ll*y*(X-1);if(res<=K) xx=mid,l=mid+1;else r=mid-1;
		}
		if(!i&&!A[i]){ans=0;break;}LL delta=4ll+8ll*xx*(xx-1),X=(LL)ceil((-2.0+sqrt(delta))/4.0);while(2ll*(X-1)*(X-1)+2ll*X-1ll*xx*(xx-1)>=0&&X>1) X--;X=max(X,1ll);LL res=1ll*(xx-1)*x+1ll*y*(X-1),tmp=K-res;
		DB ret=2.0*x/xx+1.0*y/X;while(tmp&&2ll*X*(X+1)>=1ll*xx*(xx+1)){if(tmp>x) tmp-=x,ret-=(2.0*x/((xx+1)*xx)),xx++;else ret-=(2.0*tmp/((xx+1)*xx)),tmp=0;}
		if(tmp) if(tmp<=y) ans=min(ans,-1.0*tmp/((X+1)*X)+ret);else ans=min(ans,-2.0*(tmp-y)/((xx+1)*xx)-1.0*y/((X+1)*X)+ret);else ans=min(ans,ret);
	}
	printf("%0.12lf
",ans);return 0;
}

发表回复