2019.01.30【NOIP提高组】模拟 B 组

111 篇文章 0 订阅
76 篇文章 0 订阅

JZOJ 4252 QYQ的图(深搜)

题目

给你一个 n n n个点, m m m条边的无向图,每个点有一个非负的权值 c i ci ci,现在你需要选择一些点,使得每一个点都满足:
如果这个点没有被选择,则与它有边相连的所有点都必须被选择。
问:满足上述条件的点集中,所有选择的点的权值和最小是多少?


分析

深搜


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
int n,m,a[51],ans; long long spe[51];
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 dfs(int dep,int sum,long long now){
	if (sum>=ans) return;
	if (dep>n){
		ans=sum;
		return;
	}
	if (!(now&(1ll<<dep))&&!(spe[dep]&(1ll<<dep))) dfs(dep+1,sum,now|spe[dep]);
	dfs(dep+1,sum+a[dep],now|(1ll<<dep));
}
signed main(){
	freopen("graph.in","r",stdin);
	freopen("graph.out","w",stdout);
	n=iut(); m=iut();
	for (rr int i=1;i<=n;++i) ans+=(a[i]=iut());
	for (rr int i=1;i<=m;++i){
		rr int x=iut(),y=iut();
		spe[x]|=1ll<<y,spe[y]|=1ll<<x;
	}
	dfs(1,0,0);
	return !printf("%d",ans);
}

JZOJ 4248 n染色

题目

给一个 n n n边形涂色,共有 m m m种颜色的笔,使相邻两边颜色不同的方案有多少


分析

设答案为 f [ n ] f[n] f[n],那么分类讨论新加进来的第 n n n条边

  • 当两条邻边相同时,那么等同于在 n − 2 n-2 n2条边内加入一条相同的边和一条不同的边,那也就是 f [ n − 2 ] × ( m − 1 ) f[n-2]\times(m-1) f[n2]×(m1)
  • 当两条邻边不同时,也就是在 n − 1 n-1 n1条边内加入一条与两条邻边都不同的边,那也就是 f [ n − 1 ] × ( m − 2 ) f[n-1]\times (m-2) f[n1]×(m2)

综上所述, f [ n ] = f [ n − 2 ] × ( m − 1 ) + f [ n − 1 ] × ( m − 2 ) f[n]=f[n-2]\times(m-1)+f[n-1]\times(m-2) f[n]=f[n2]×(m1)+f[n1]×(m2)
那考虑优化,首先可以矩阵乘法~~,但是这道题不需要~~
那可以简化这条式子
f [ n ] + f [ n − 1 ] = f [ n − 1 ] × ( m − 2 ) + f [ n − 2 ] × ( m − 1 ) + f [ n − 1 ] = ( f [ n − 1 ] + f [ n − 2 ] ) × ( m − 1 ) f[n]+f[n-1]=f[n-1]\times(m-2)+f[n-2]\times(m-1)+f[n-1]=(f[n-1]+f[n-2])\times(m-1) f[n]+f[n1]=f[n1]×(m2)+f[n2]×(m1)+f[n1]=(f[n1]+f[n2])×(m1)
那就可以得到 f [ n ] + f [ n − 1 ] = ( m − 1 ) n m f[n]+f[n-1]=(m-1)^nm f[n]+f[n1]=(m1)nm
( f [ n ] + f [ n − 1 ] ) − ( f [ n − 1 ] + f [ n − 2 ] ) ± ⋯ ± ( f [ 1 ] − f [ 0 ] = m ) = f [ n ] (f[n]+f[n-1])-(f[n-1]+f[n-2])\pm\dots\pm(f[1]-f[0]=m)=f[n] (f[n]+f[n1])(f[n1]+f[n2])±±(f[1]f[0]=m)=f[n]
解开后用等比数列求和即可


代码

#include <cstdio>
#define rr register
using namespace std;
typedef long long ll; const ll mod=1000000007;
ll ans,n,m;
inline ll ksm(ll x,ll y){
	rr ll ans=1;
	for (;y;y>>=1,x=(x*x)%mod)
	    if (y&1) ans=(ans*x)%mod;
	return ans;
}
signed main(){
	freopen("color.in","r",stdin);
	freopen("color.out","w",stdout);
	scanf("%lld%lld",&n,&m);
	ans=(m-1)*((n&1)?-1:1)+ksm(m-1,n%(mod-1));
	return !printf("%lld",ans%mod);
} 

JZOJ 4249 游戏(贪心)

题目

从原点往正方向跳,若从 j j j跳到 i i i那么可以获得 a [ i ] × ( i − j ) a[i]\times(i-j) a[i]×(ij)的分数,问如何使分数最大


分析

那么这道题可能是题目出的比较玄学,本来好像要斜率优化的,现在只需要维护后缀最大值贪心求解


代码

#include <cstdio>
#include <cctype>
#define rr register
#define max(a,b) ((a>b)?(a):(b))
using namespace std;
int n,a[100001],mx[100001],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;
} 
signed main(){
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	n=iut(); for (rr int i=1;i<=n;++i) a[i]=iut();
	mx[n]=a[n]; rr int ls=0;
	for (rr int i=n-1;i;--i) mx[i]=max(mx[i+1],a[i]);
	for (rr int i=1;i<=n;++i)
	if (a[i]==mx[ls+1])
		ans+=(i-ls)*a[i],ls=i;
	return !printf("%d",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值