2019.01.29【NOIP提高组】模拟 B 组

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sugar_free_mint/article/details/86692272

JZOJ 4244 yi

分析

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


JZOJ 4245 er

题目

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

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

分析

首先,修改的次序肯定是先赋值,再增加,最后乘,从大到小排序 x x ,首先 n = 1 n=1 的时候很好处理,我就不解释了,问题是 n = 2 n=2 怎么处理,那首先乘在一起是不受影响的,那么关键是处理加,那深搜应该是会爆炸的,只想到了动态规划
f [ i ] [ j ] f[i][j] 表示选完前 i i 个(已排序),第一个装备威力为 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 ] = m a x { f [ i 1 ] [ j ] + j a d d [ i ] } f[i][j]=max\{f[i-1][j]+j*add[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) 的最短路且其长度为奇数


分析

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


代码

#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;
}

猜你喜欢

转载自blog.csdn.net/sugar_free_mint/article/details/86692272
今日推荐