义乌集训7.14 contest 7题解

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<<'\n';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<<'\n';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 \times 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('\n');}
	FastIO& operator >> (char&ch){while(ch=nc(),ch==' '||ch=='\n');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!='\n'){*(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])<<'\n';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,1\leq 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('\n');}
	FastIO& operator >> (char&ch){while(ch=nc(),ch==' '||ch=='\n');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!='\n'){*(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<<'\n';return 0;
}

T4:

Description:

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

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

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

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

Input:

​ 第一行三个整数 \(n,m,k\),表示点数,边数与初始 \(\texttt{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 \times (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\%\) 的数据,满足 \(0\le n,m\le 5\times 10^3\)\(0\le k\le 10^9\)

题目分析:

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

​ 我们枚举每个 \(i\),通过二分来确定分配 \(\texttt{RMB}\) 的方案。我们考虑到对于相交的路径会产生 \(\frac{2}{a}\) 的贡献,而剩余的路径的贡献为 \(\frac{1}{a}\)。我们假设给每条相交的路径上的边分配 \(x\) \(\texttt{RMB}\) ,则给不相交的路径上的每条边分配的 \(\texttt{RMB}\)\(y\) 满足 \(\frac{2}{x-1}-\frac{2}{x} \geq \frac{1}{y}-\frac{1}{y+1}\),解出满足该方程的最大的 \(y\) ,判断给定的 \(k\) \(\texttt{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\n",ans);return 0;
}
posted @ 2021-07-22 20:54  OdtreePrince  阅读(166)  评论(1编辑  收藏  举报