我的来时路-算法竞赛-华中农业大学第十四届程序设计竞赛(同步赛)题解

A

思路:模拟一下就行。
 

ll k;
ll mx[maxn],mn[maxn];
ll b[maxn],r[maxn];
ll p[maxn][maxn],v[maxn][maxn];
ll x[maxn],y[maxn];
ll ans[maxn][2];
void solve()
{ 	
   cin>>n>>m>>k;
   for(int i=1;i<=m;i++)
   {
   	 cin>>b[i];
   	 mn[i]=110;
   	 mx[i]=-2;
   }
   for(int i=1;i<=m;i++)
   {
   	 cin>>r[i];
   }
   for(int i=1;i<=m;i++)
   {
   	  for(int j=1;j<=n;j++)
   	  {
   	    cin>>p[i][j];	
   	    mn[i]=min(mn[i],p[i][j]);
   	    mx[i]=max(mx[i],p[i][j]);
	  }
   }
   for(int i=1;i<=n;i++)
   {
   	 cin>>x[i];
   }
   for(int i=1;i<=n;i++)
   {
   	 cin>>y[i];
   }
   for(int i=1;i<=m;i++)
   {
   	  for(int j=1;j<=n;j++)
   	  {
   	    if(p[i][j]==-1)
	    {
	       v[j][i]=0;
		   continue;	
		}	
		if(mx[i]<=0)
		v[j][i]=b[i];
		else v[j][i]=min(b[i]+r[i]*p[i][j]/mx[i],100*1ll);
	  }
   }
   for(int i=1;i<=n;i++)
   {
   	  multiset<ll>st;
   	  ll s=0;
   	  for(int j=1;j<=m;j++)
   	  {
   	    st.insert(v[i][j]);
   	    s+=v[i][j];
   	    if(st.size()>k)
   	    {
   	       s-=(*st.begin());
		   st.erase(st.begin());
		}
	  }
	  ans[i][0]=s/k;
   }
   for(int i=1;i<=n;i++)
   {
   	 ans[i][1]=x[i]/60+y[i];
   	 ans[i][1]=min(ans[i][1],100*1ll);
   }
   ll cnt=0;
   for(int i=1;i<=n;i++)
   {
   	  if(min(ans[i][0],ans[i][1])>=50&&max(ans[i][0],ans[i][1])>=60)
   	  cnt++;
   }
   cout<<cnt<<'\n';
   
}

B

思路:简单题

void solve()
{ 	
   for(int i=1;i<=3;i++)
   cin>>a[i];
   sort(a+1,a+1+3);
   if(a[1]<a[2])
   {
   	 cout<<a[2]<<" "<<a[1]<<" "<<a[3];
   }else cout<<-1;
}

C

思路:根据均值不等式,两次二分,分别求最大的小于等于sum/2的数,最小的大于等于sum/2的数。
 

ll q,pre[maxn];
ll cal(int x,int y,int k)
{
	ll v1=pre[k]-pre[x-1];
	ll v2=pre[y]-pre[k];
	return abs(v1-v2);
}
void solve()
{ 	
   cin>>n>>q;
   for(int i=1;i<=n;i++)
   {
   	 cin>>a[i];
   	 pre[i]=pre[i-1]+a[i];
   }
   while(q--)
   {
   	 int x,y;
   	 cin>>x>>y;
   	 sum=pre[y]-pre[x-1];
   	 int l=x,r=y-1;
   	 int pos1=-1;
   	 while(l<=r)
   	 {
   	   int mid=(l+r)>>1;
	   if(pre[mid]-pre[x-1]<=sum/2)
	   {
	     pos1=max(pos1,mid);
		 l=mid+1;   	
	   }else r=mid-1;
	 }
	 ll v1=(pos1==-1?1e17:cal(x,y,pos1));
	 l=x;r=y-1;
	 int pos2=n+1;
	 while(l<=r)
	 {
	 	int mid=(l+r)>>1;
	 	if(pre[mid]-pre[x-1]>=sum/2)
	 	{
	 	  pos2=min(pos2,mid);
		  r=mid-1;	
		}else l=mid+1;
	 }
	 ll v2=(pos2==n+1?1e17:cal(x,y,pos2));
	 ll k;
	 if(v1<=v2)
	 k=pos1;
	 else k=pos2;
	 ll fz=pre[y]-pre[x-1];
	 ll fm=(pre[k]-pre[x-1])%mode2*(pre[y]-pre[k])%mode2;
	 fm=(fm%mode2+mode2)%mode2;
	 ans=fz%mode2*ksm(fm,mode2-2,mode2)%mode2;
	 cout<<ans<<" ";
   }
   cout<<'\n';
   
}

D

思路:简单题
 

void solve()
{ 	
   cin>>n;
   set<int>st;
   for(int i=1;i<=n;i++)
   {
   	 st.insert(i);
   }
   for(int i=1;i<=n;i++)
   {
   	 int x;
   	 cin>>x;
   	 if(st.find(x)!=st.end())
   	 st.erase(st.find(x));
   }
   if(st.size()==0)
   cout<<-1<<'\n';
   else cout<<(*st.begin())<<'\n';
}

E

思路:因为b数组最大值为1e8,所以dp一下就行。

ll dp[maxn];
void solve()
{ 	
   cin>>n;
   for(int i=1;i<=n;i++)
   {
   	 cin>>a[i];
   	 dp[i]=0;
   }
   dp[0]=1;
   for(ll i=1;i-1<=n;i++)
   {
   	  if(dp[i-1]==0)
   	  continue;
   	  ll L=i+1,R=min(n,i+700);
   	  ll v1=a[i],v2=0;
   	  for(ll j=i+1;j<=R;j++)
   	  {
   	    v2=v2+(j-L+1)*(j-L+1)*a[j];
		if(v2==v1)
		{
		  dp[j]=1;
//		  cer2(i,j);	
		}	
	  }
	  v2=0;
	  for(ll j=i;j<=R-1;j++)
	  {
	  	v2=v2+(j-i+1)*(j-i+1)*a[j];
	  	if(v2==a[j+1])
	  	{
	  	  dp[j+1]=1;
//		  cer2(i,j+1);	
		}
	  }
   }
   if(dp[n])
   cout<<"YES"<<'\n';
   else cout<<"NO"<<'\n';
}

G

思路:类似数位dp的思想,数位dfs一下。

ll l,r;
set<ll>st;
bool check(ll s)
{
	ll last=s%10;
	s/=10;
	while(s)
	{
		ll v=s%10;
		s/=10;
		if(abs(v-last)!=1)
		return false;
		last=v;
	}
	return true;
}
void dfs(int cnt,ll s,int last,bool ok)
{
	if(s>r)
	return;
	if(cnt>=19)
	{
		if(s>=l&&s<=r)
		ans++;
		return;
	}
	if(cnt==1)
	{
		for(int i=0;i<=9;i++)
	    {
		 if(s*10+i>r)
		 return;
		 dfs(cnt+1,s*10+i,i,(ok&&i==0));
	   }
	}else{
		if(ok)
		{
			for(int i=0;i<=9;i++)
			{
				if(s*10+i>r)
				break;
				dfs(cnt+1,s*10+i,i,(ok&&i==0));
			}
		}else{
			if(last+1<=9)
			dfs(cnt+1,s*10+(last+1),last+1,false);
			if(last-1>=0)
			dfs(cnt+1,s*10+(last-1),last-1,false);
		}
	}
}
void solve()
{ 	
   cin>>l>>r;
   dfs(1,0,0,1);
   cout<<ans<<'\n';
}

H

思路:简单题。

ll b[maxn];
void solve()
{ 	
   cin>>n;
   map<int,ll>p;
   for(int i=1;i<=n;i++)
   {
   	 cin>>a[i];
   	 p[a[i]]++;
   }
   for(int i=1;i<=n;i++)
   {
   	 cin>>b[i];
   }
   ans=0;
   for(int i=1;i<=n;i++)
   {
   	 p[a[i]]--;
   	 ans+=p[a[i]];
   }
   p.clear();
   for(int i=1;i<=n;i++)
   {
   	 p[b[i]]++;
   }
   for(int i=1;i<=n;i++)
   {
   	 p[b[i]]--;
   	 ans+=p[b[i]];
   }
   cout<<ans<<'\n';
   
}

I

思路:基环树模板题。

int fa[maxn],st[maxn][30],id1,id2,dep[maxn];
int find(int x)
{
	return fa[x]==x?fa[x]:fa[x]=find(fa[x]);
}
bool same(int x,int y)
{
	return (find(x)==find(y));
}
void hb(int x,int y)
{
	int fx=find(x),fy=find(y);
	if(fx==fy)
	return;
	fa[fx]=fy;
}
void dfs(int u,int p)
{
	dep[u]=dep[p]+1;
	st[u][0]=p;
	for(int i=1;i<=25;i++)
	{
		if(st[u][i-1]==0)
		break;
		st[u][i]=st[st[u][i-1]][i-1];
	}
	for(auto it:vt[u])
	{
		if(it==p)
		continue;
		dfs(it,u);
	}
}
int LCA(int x,int y)
{
	if(dep[x]<dep[y])
	swap(x,y);
	
	for(int i=25;i>=0;i--)
	{
		if(dep[st[x][i]]>=dep[y])
		x=st[x][i];
	}
	if(x==y)
	return x;
	
	for(int i=25;i>=0;i--)
	{
		if(st[x][i]!=st[y][i])
		{
			x=st[x][i];
			y=st[y][i];
		}
	}
	return st[x][0];
}
ll dis(int x,int y)
{
	return dep[x]+dep[y]-2*dep[LCA(x,y)];
}
void solve()
{ 	
   int q;
   cin>>n>>q;
   for(int i=1;i<=n;i++)
   {
   	 fa[i]=i;
   }
   for(int i=1;i<=n;i++)
   {
   	 int x,y;
   	 cin>>x>>y;
   	 if(same(x,y))
   	 {
   	   id1=x;
	   id2=y;
	   continue;	
	 }
	 hb(x,y);
	 vt[x].pb(y);
	 vt[y].pb(x);
   }
   dfs(1,0);
   while(q--)
   {
   	  int s,t;
   	  ll k;
   	  cin>>s>>t>>k;
   	  ll d=dis(s,t);
   	  if(d<=k&&((k-d)%2==0))
   	  {
   	    cout<<"YES"<<'\n';
		continue;
	  }
	  d=dis(s,id1)+1+dis(t,id2);
	  if(d<=k&&((k-d)%2==0))
   	  {
   	    cout<<"YES"<<'\n';
		continue;	
	  }
	  d=dis(s,id2)+1+dis(t,id1);
	  if(d<=k&&((k-d)%2==0))
   	  {
   	  	cout<<"YES"<<'\n';
   	    continue;
	  }
	  cout<<"NO"<<'\n';
   }
}

J

思路:先预处理求每个点的战斗力,再dfs+dp。
 

vector<int>ed[maxn];
ll b[maxn];
ll sz[maxn],dp[maxn][2009];
int find_lsh_id(ll x)
{
	int pos=lower_bound(vt.begin(),vt.end(),x)-vt.begin()+1;
	return pos;
}
struct node{
	ll l,r,s;
}tr[maxn<<2];
void push(int u)
{
	tr[u].s=tr[u<<1].s+tr[u<<1|1].s;
}
void build(int u,int l,int r)
{
	tr[u].l=l;
	tr[u].r=r;
	if(l==r)
	{
		tr[u].s=0;
		return;
	}
	int mid=(l+r)>>1;
	build(u<<1,l,mid);
	build(u<<1|1,mid+1,r);
	push(u);
	return;
}
void update(int u,int l,int r,int x,int v)
{
	if(l==r&&l==x)
	{
		tr[u].s+=v;
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid)
	update(u<<1,l,mid,x,v);
	else update(u<<1|1,mid+1,r,x,v);
	push(u);
	return;
}
ll query(int u,int l,int r,int cnt)
{
	if(l==r)
	{
		return l;
	}
	int mid=(l+r)>>1;
	if(tr[u<<1].s>=cnt)
	{
		return query(u<<1,l,mid,cnt);
	}else return query(u<<1|1,mid+1,r,cnt-tr[u<<1].s);
}
void dfs(int u,int fa,int cnt)
{
	update(1,1,n,b[u],1);
	dp[u][1]=vt[query(1,1,n,cnt/2+1)-1];
	for(auto it:ed[u])
	{
		if(it==fa)
		continue;
		dfs(it,u,cnt+1);
	}
	update(1,1,n,b[u],-1);
}
void dfs1(int u,int fa)
{
	sz[u]=1;
	for(auto it:ed[u])
	{
		if(it==fa)
		continue;
		dfs1(it,u);
		
		ll res[m+1];
		for(int i=0;i<=m;i++)
		res[i]=0;
		
		for(int i=1;i<=min(sz[u],m);i++)
		{
			for(int j=0;j<=min(sz[it],m-i);j++)
			{
				res[i+j]=max(res[i+j],dp[u][i]+dp[it][j]);
			}
		}
		for(int i=1;i<=m;i++)
		dp[u][i]=res[i];
		sz[u]+=sz[it];
	}
}
void solve()
{ 	
   cin>>n>>m;
   for(int i=1;i<=n;i++)
   {
   	 cin>>a[i];
   	 vt.pb(a[i]);
   }
   for(int i=1;i<=n-1;i++)
   {
   	 int x,y;
   	 cin>>x>>y;
   	 ed[x].pb(y);
   	 ed[y].pb(x);
   }
   sort(all(vt));
   vt.erase(unique(vt.begin(),vt.end()),vt.end());
   for(int i=1;i<=n;i++)
   {
   	 b[i]=find_lsh_id(a[i]);
   }
   build(1,1,n);
   dfs(1,0,1);
   dfs1(1,0);
   ans=0;
   for(int i=1;i<=m;i++)
   {
   	 ans=max(ans,dp[1][i]);
   }
   cout<<ans;
}

K

思路:简单题。

void solve()
{ 	
   cin>>str;
   n=str.length();
   if(n==1)
   {
   	 cout<<str<<'\n';
   	 return;
   }
   for(int i=0;i+1<n;i++)
   {
   	 if(str[i]<str[i+1])
   	 {
   	   swap(str[i],str[i+1]);
	   break;	
	 }
   }
   cout<<str<<'\n';
}

L

思路:打表

ll x,y,k;
void solve()
{ 	
   cin>>k>>x>>y;
   
   if(x==y)
   {
   	 cout<<x<<'\n';
   	 return;
   }
   ll last=(x+y)/2;
   for(int i=2;i<k;i++)
   {
   	 last=(last+x)/2;
   	 if(last==x)
   	 break;
   }
   cout<<min((x+y)/2,last)<<'\n';
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值