GirlNowcoder2018题解

GirlNowcoder

T1

题面很迷的一道题.大概主要有两个比较坑的点

1.q秒下载q-1的内容意思是每秒下载 q 1 q \frac{q-1}{q} 的内容.

2.下载了s秒意思是下载了s秒的内容而不是实际等待下载了s秒

然后s,t,q都很小 按照题意模拟即可(出题人这堆歧义是要被语文老师吊起来打的啊

然后code

https://paste.ubuntu.com/p/hN952Y3d4t/

T2

题意大概是这样的

定义 f ( x , y ) = ( x y ) y , m x ( x ) = m a x ( f ( x , y ) ( 1 y x ) ) f(x,y)={(\frac{x}{y})}^y,mx(x)=max(f(x,y)(1\leq y \leq x))
M ( x ) = x [ m x ( x ) ] + x [ m x ( x ) ] M(x)= -x [mx(x)为无限循环小数] +x[mx(x)为有限小数]
要求的内容是

$\sum_{i=5}^{n}M(i) $

范围是 n 1 0 5 n\leq 10^5

首先考虑的是mx(x)怎么求(因为直接求M(x)似乎不大可行

在这个时候考虑 f ( x , y ) f(x,y) f ( x , y + 1 ) f(x,y+1) 的区别

在这之后感性理解感觉是一个单峰函数

f ( x , y ) f ( x , y + 1 ) f(x,y)\leq f(x,y+1)

x y y y x y + 1 ( y + 1 ) y + 1 \frac{x^y}{y^y}\leq \frac{x^{y+1}}{(y+1)^{y+1}}

然后移项一下就是

x ( y + 1 ) y / ( y y ) ( y + 1 ) x\geq{(y+1)}^{y}/(y^y) *(y+1)

然后因为直接把(y+1)y和yy求出来似乎误差很大所以说考虑直接对 y + 1 y \frac{y+1}{y} 快速幂以下即可.

在知道x,y之后怎么判断是否是无限循环小数.只需要除掉2,5(因为是十进制的分数),然后判断一下gcd的关系即可

#include<bits/stdc++.h>
#define ll long long
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define A first
#define B second
#define db long double
#define lowbit(p) (p&(-p))
using namespace std;
void read(int &x){
	x=0; char c=getchar(); int p=1;
	for (;c<48;c=getchar())if (c=='-')p=-1;
	for (;c>47;c=getchar())x=(x<<1)+(x<<3)+(c^48);
	x*=p;
}
void read(ll &x){
	x=0; char c=getchar(); int p=1;
	for (;c<48;c=getchar())if (c=='-')p=-1;
	for (;c>47;c=getchar())x=(x<<1)+(x<<3)+(c^48);
	x*=p;
}
void Min(int &x,int y){
	if (x>y)x=y;
}
void Max(int &x,int y){
	if (x<y)x=y;
}
void Min(ll &x,ll y){
	if (x>y)x=y;
}
void Max(ll &x,ll y){
	if (x<y)x=y;
}
/*

f(x,y)=x^y/(y^y)
y<=x
M(x)=max(f(x,y))=max{ x^y/(y^y)  }

x^y		/(y^y)
x^(y+1)/((y+1)^(y+1)

x*(y^y)>(y+1)^(y+1)
x>(y+1)^(y+1)/(y^y)


x*y^y>(y+1)^(y+1) 
*/
int cal(int x){
	for (;x%5==0;x/=5);
	for (;x%2==0;x/=2);
	return x;
}
ll gcd(ll a,ll b){
	if (b==0)return a;
	return gcd(b,a%b);
}
db ksm(db a,int b){
	db res=1;
	for (;b;b>>=1){
		if(b&1)res=res*a;
		a=a*a;
	}
	return res;
}
db get(ll x){
	db res=(x+1.0)*ksm((x+1.0)/x,x);
	return res;
}
int main(){
//	freopen("1.in","r",stdin);
	ll x,y=1,k,g,res=0,n;
	db v=get(y);
	read(n);
	for (x=5;x<=n;x++){
		for (;y<=x&&x>=v;){
			/*
			x>(y+1)^(y)/(y^y) *(y+1)
			*/
			y++;
			v=get(y);
			k=cal(y);
		}
		g=gcd(cal(x),k);
		if (k/g!=1){
			res+=x;
		}
		else {
			res-=x;
		}
	}
	printf("%lld\n",res);
	return 0;
}

T3

具体题意记不清楚了…大概是任意x个塔内要有c的标记了的塔,然后n个塔里面有m个已经被标记的位置,然后最少要标记多少个.

那么贪心的考虑问题,从前往后扫遇到一个长度为x的区间个数不足c个那么就把当前区间末尾没有被标记的塔标记了即可.

这个过程用队列维护一下即可.

#include<bits/stdc++.h>
#define ll long long
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define A first
#define B second
#define db double
#define lowbit(p) (p&(-p))
using namespace std;
void read(int &x){
	x=0; char c=getchar(); int p=1;
	for (;c<48;c=getchar())if (c=='-')p=-1;
	for (;c>47;c=getchar())x=(x<<1)+(x<<3)+(c^48);
	x*=p;
}
void read(ll &x){
	x=0; char c=getchar(); int p=1;
	for (;c<48;c=getchar())if (c=='-')p=-1;
	for (;c>47;c=getchar())x=(x<<1)+(x<<3)+(c^48);
	x*=p;
}
void Min(int &x,int y){
	if (x>y)x=y;
}
void Max(int &x,int y){
	if (x<y)x=y;
}
void Min(ll &x,ll y){
	if (x>y)x=y;
}
void Max(ll &x,ll y){
	if (x<y)x=y;
}
#define M 1000005
int q[M],n,x,c,m,cnt;
bool mark[M];
int main(){
//	freopen("1.in","r",stdin);
	read(n); read(x); read(c); read(m);
	int i,p;
	for (i=1;i<=m;i++){
		read(p);
		mark[p]=1;
	}
	int res=0,r=0;
	for (i=1;i<=x;i++){
		if (mark[i]){
			cnt++;
		}
		else{
			q[++r]=i;
		}
	}
	for (;cnt<c;){
		p=q[r]; r--;
		mark[p]=1;
		cnt++;
		res++;
	}
	for (;i<=n;i++){
		if (mark[i]){
			cnt++;
		}
		else{
			q[++r]=i;
		}
		if (mark[i-x]){
			cnt--;
		}
		for (;cnt<c;){
			p=q[r]; r--;
			mark[p]=1;
			cnt++;
			res++;
		}
	}
	
	printf("%d\n",res);
	return 0;
}

T4

给定一个长度为n的正整数数组求所有的 f ( k ) i = 1 n a [ k ] a [ i ] + 1 ( 1 k n ) f(k)\sum_{i=1}^{n}\frac{a[k]}{a[i]+1} (1\leq k \leq n)

因为a的范围特别小所以说计数一下.然后考虑这个数字对别的数字的贡献(讲不清楚qwqqq…)

大概就是有cnt[x]个x-1出现在a数组内,那么

a [ i ] [ 0 , x ) a[i]\in[0,x) 的贡献为0
a [ i ] [ x , 2 x ) a[i]\in[x,2*x) 的贡献为1
a [ i ] [ 2 x , 3 x ) a[i]\in[2*x,3*x) 的贡献为2

以此类推.

然后用差分的思想来解决这个贡献的统计,只需要在x,2x,3x…上都加上cnt[x]最后前缀和滚一遍即可.

这样操作的复杂度是 i = 1 n n i \sum_{i=1}^{n}\frac{n}{i} 的,然而大概就是nlogn左右

#include<bits/stdc++.h>
#define ll long long
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define A first
#define B second
#define db double
#define lowbit(p) (p&(-p))
using namespace std;
void read(int &x){
	x=0; char c=getchar(); int p=1;
	for (;c<48;c=getchar())if (c=='-')p=-1;
	for (;c>47;c=getchar())x=(x<<1)+(x<<3)+(c^48);
	x*=p;
}
void read(ll &x){
	x=0; char c=getchar(); int p=1;
	for (;c<48;c=getchar())if (c=='-')p=-1;
	for (;c>47;c=getchar())x=(x<<1)+(x<<3)+(c^48);
	x*=p;
}
void Min(int &x,int y){
	if (x>y)x=y;
}
void Max(int &x,int y){
	if (x<y)x=y;
}
void Min(ll &x,ll y){
	if (x>y)x=y;
}
void Max(ll &x,ll y){
	if (x<y)x=y;
}
#define M 1000005
int cnt[M],n,a[M];
ll res[M];
int main(){
//	freopen("1.in","r",stdin);
	read(n);
	int i,j;
	for (i=1;i<=n;i++){
		read(a[i]);
		cnt[a[i]+1]++;
	}
	for (i=1;i<M;i++){
		if (cnt[i]){
			for (j=i;j<M;j+=i){
				res[j]+=cnt[i];
			}
		}
		res[i]+=res[i-1];
	}
	for (i=1;i<n;i++){
		printf("%lld ",res[a[i]]);
	}
	printf("%lld\n",res[a[i]]);
	
	return 0;
}

T5

普通的图论…

大概就是要选择一些边,满足所有点走这些边能走出最短路并且这些边的边权和最小.

也是一个贪心?dijkstra的过程中在维护最短路的同时维护一个在当前最短路基础上的能从已经确定最短路的点走过来的最小边权.最后加起来就是答案了.

#include<bits/stdc++.h>
#define ll long long
#define mp make_pair
#define pb push_back
#define pii pair<ll,ll>
#define A first
#define B second
#define db double
#define lowbit(p) (p&(-p))
using namespace std;
void read(int &x){
	x=0; char c=getchar(); int p=1;
	for (;c<48;c=getchar())if (c=='-')p=-1;
	for (;c>47;c=getchar())x=(x<<1)+(x<<3)+(c^48);
	x*=p;
}
void read(ll &x){
	x=0; char c=getchar(); int p=1;
	for (;c<48;c=getchar())if (c=='-')p=-1;
	for (;c>47;c=getchar())x=(x<<1)+(x<<3)+(c^48);
	x*=p;
}
void Min(int &x,int y){
	if (x>y)x=y;
}
void Max(int &x,int y){
	if (x<y)x=y;
}
void Min(ll &x,ll y){
	if (x>y)x=y;
}
void Max(ll &x,ll y){
	if (x<y)x=y;
}

#define M 200005
struct ed{
	int x;
	ll l;
	int nx;
}e[M<<1];
int nx[M],ecnt=1;
ll dis[M],d[M];

void add(int x,int y,ll l){
	e[ecnt]=(ed){y,l,nx[x]};
	nx[x]=ecnt++;
}
bool mark[M];
priority_queue< pii >q;
void dij(int x){
	memset(dis,63,sizeof(dis));
	dis[x]=0;
	q.push(mp(-dis[x],x));
	for (;!q.empty();){
		x=q.top().B; q.pop();
		if (mark[x])continue;
		mark[x]=1;
//		printf("%d %lld %lld\n",x,dis[x],d[x]);
		for (int i=nx[x];i;i=e[i].nx){
			if (dis[x]+e[i].l<dis[e[i].x]||(dis[x]+e[i].l==dis[e[i].x]&&d[e[i].x]>e[i].l)){
				d[e[i].x]=e[i].l;
				dis[e[i].x]=dis[x]+e[i].l;
				q.push(mp(-dis[e[i].x],e[i].x));
			}
		}	
	}
}
int n,m;

int main(){
//	freopen("1.in","r",stdin);
	read(n); read(m);
	int i,s,x,y;
	ll v;
	for (i=1;i<=m;i++){
		read(x); read(y); read(v);
		add(x,y,v);
		add(y,x,v);
	}
	read(s);
	dij(s);
	ll res=0;
	for (i=1;i<=n;i++)if (s!=i){
		res+=d[i];
	}
	printf("%lld\n",res);
	return 0;
}

T6

我仍然认为题目错了.

或者我语文不好.

吐槽

所以到底是语文老师的问题还是我的问题还是出题人的问题还是出题人的语文老师的问题啊

然后就是"你正在考试请独立思考"

还不如无可奉告呢

猜你喜欢

转载自blog.csdn.net/Umbrella__/article/details/85232453