2019.01.29【NOIP提高组】模拟 B 组

本文深入解析JZOJ4244、4245、4246三道算法题目的解题思路与代码实现。涵盖贪心算法、动态规划及最短路径算法,通过具体实例展示算法设计与优化技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JZOJ 4244 yi

分析

真是一道大难题,主要是往返这两个字比较坑,剩下的贪心搞定,题目过水,就不贴代码了


JZOJ 4245 er

题目

给你 1 ∼ 2 1\sim 2 12个数,然后让你经过 k k k次修改后使它(们)乘积最大,输出自然对数
修改如下:

  • q = 1 q=1 q=1,使某个数变为 x x x(最多只有一次)
  • q = 2 q=2 q=2,使某个数增加 x x x
  • q = 3 q=3 q=3,使某个数乘 x x x

分析

首先,修改的次序肯定是先赋值,再增加,最后乘,从大到小排序 x x x,首先 n = 1 n=1 n=1的时候很好处理,我就不解释了,问题是 n = 2 n=2 n=2怎么处理,那首先乘在一起是不受影响的,那么关键是处理加,那深搜应该是会爆炸的,只想到了动态规划
f [ i ] [ j ] f[i][j] f[i][j]表示选完前 i i i个(已排序),第一个装备威力为 j j j,两个装备威力的最大乘积,那么
f [ i ] [ j + a d d [ i ] ] = m a x { f [ i − 1 ] [ j ] + ( s u m [ i − 1 ] − j ) ∗ a d d [ i ] } f[i][j+add[i]]=max\{f[i-1][j]+(sum[i-1]-j)*add[i]\} f[i][j+add[i]]=max{f[i1][j]+(sum[i1]j)add[i]}
f [ i ] [ j ] = m a x { f [ i − 1 ] [ j ] + j ∗ a d d [ i ] } f[i][j]=max\{f[i-1][j]+j*add[i]\} f[i][j]=max{f[i1][j]+jadd[i]}
然后由于会赋值,所以要跑3次


代码

#include <bits/stdc++.h>
#define rr register
using namespace std;
int n,m,k,a0,a1,aux,n1,n2,sum1[101],add[101];
double sum2[101],ans;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void answ(int a0,int a1){
    rr int f[2][200001],res[101]; memset(f[0],0xcf,sizeof(f[0]));
	sum1[0]=a0+a1; memset(res,0,sizeof(res)); res[0]=f[0][a0]=a0*a1;
	for (rr int i=1;i<=n1;++i) sum1[i]=sum1[i-1]+add[i];
	for (rr int i=1;i<=k;++i){
		memset(f[i&1],0xcf,sizeof(f[i&1]));
		for (rr int j=a0;j<=sum1[i];++j){
			f[i&1][j]=max(f[i&1][j],f[1-(i&1)][j]+add[i]*j);
			if (j+add[i]<=sum1[i])
			f[i&1][j+add[i]]=max(f[i&1][j+add[i]],f[1-(i&1)][j]+add[i]*(sum1[i-1]-j));
			res[i]=max(res[i],f[i&1][j]);
		}
	}
	for (rr int i=0;i<=k;++i)
		ans=max(ans,log(res[min(i,n1)])+sum2[min(k-i,n2)]);
}
inline void func(){
     answ(a0,a1);
     if (aux) --k,answ(aux,a1),answ(a0,aux);
}
signed main(){
	n=iut(); m=iut(); k=iut(); 
	a0=iut(); if (n>1) a1=iut(); sum1[0]=a0+a1;
	for (rr int i=1;i<=m;++i){
		rr int x=iut(),y=iut();
	    if (x==3&&y==1) --i,--m;
	    else{
	    	if (x==1) aux=y;
	    	else if (x==2) add[++n1]=y;
	    	else sum2[++n2]=log(y);
		}
	}
	sort(add+1,add+1+n1); reverse(add+1,add+1+n1);
	sort(sum2+1,sum2+1+n2); reverse(sum2+1,sum2+1+n2);
	for (rr int i=1;i<=n1;++i) sum1[i]=sum1[i-1]+add[i];
	for (rr int i=1;i<=n2;++i) sum2[i]+=sum2[i-1];
	if (n==1){
	    for (rr int i=0;i<=k;++i){
	    	ans=max(ans,log(sum1[min(i,n1)])+sum2[min(k-i,n2)]);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
	    	if (i<k&&aux) ans=max(ans,log(sum1[min(i,n1)]+aux-a0)+sum2[min(k-i-1,n2)]);
		}
	} 
	else func();
	return !printf("%.3lf",ans);
}

JZOJ 4246 san

题目

问每个点经过多少个无序点对 ( a , b ) (a,b) (a,b)的最短路且其长度为奇数


分析

那么这道题首先知道 O ( n 3 ) O(n^3) O(n3)是过不了的,所以要另辟蹊()径,朴素的算法计算冗余的地方就是每条路径都得算一次,这就导致了时间巨大,那该怎么办呢,首先对于每个点先求一次单源最短路径,然后其实这个图已经变成了有向无环图,那么对于每个点统计子节点的方案和,然后再相加即可


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#include <deque>
#define rr register
using namespace std;
struct node{int y,w,next;}e[6011]; bool v[1001];
int n,m,k=1,ls[1001],ans[1001],dis[1001],t[1001];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline void add(int x,int y,int w){
	e[++k]=(node){y,w,ls[x]}; ls[x]=k;
}
inline void dfs(int x,int fa){
	if (dis[x]&1) t[x]=1; else t[x]=0;
	for (rr int i=ls[x];i;i=e[i].next)
	if (e[i].y!=fa&&dis[e[i].y]==dis[x]+e[i].w){
		dfs(e[i].y,x);
		t[x]+=t[e[i].y];
	}
	ans[x]+=t[x];
}
inline void spfa(int s){
	memset(dis,127/3,sizeof(dis)); dis[s]=0;
	memset(v,0,sizeof(v)); v[s]=1;
	rr deque<int>q; q.push_back(s);
	while (q.size()){
		rr int x=q.front(); q.pop_front();
		for (rr int i=ls[x];i;i=e[i].next)
		if (dis[e[i].y]>dis[x]+e[i].w){
			dis[e[i].y]=dis[x]+e[i].w;
			if (!v[e[i].y]){
				v[e[i].y]=1;
				if (q.size()&&dis[e[i].y]<dis[q.front()]) q.push_front(e[i].y);
				    else q.push_back(e[i].y);
			}
		}
		v[x]=0;
	}
	dfs(s,0);
}
signed main(){
	n=iut();
	for (rr int m=iut();m;--m){
		rr int x=iut(),y=iut(),w=iut();
		add(x,y,w); add(y,x,w);
	}
	for (rr int i=1;i<=n;++i) spfa(i);
	for (rr int i=1;i<=n;++i) print(ans[i]),putchar(10);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值