2018.02.05【GDOI2018】模拟C组

111 篇文章 0 订阅
99 篇文章 1 订阅

向dalao致敬

JZOJ NO.1 公牛和母牛

分析

dp, f [ i ] f[i] f[i]表示 i i i头牛的方案
当母牛时,加入一头牛。
当公牛时,为加入 k k k头母牛。
f [ i ] = f [ i − 1 ] + 1 ( i &lt; = k ) f[i]=f[i-1]+1 (i&lt;=k) f[i]=f[i1]+1(i<=k)
f [ i ] = f [ i − 1 ] + f [ i − k ] ( i &gt; k ) f[i]=f[i-1]+f[i-k] (i&gt;k) f[i]=f[i1]+f[ik](i>k)


代码

#include <cstdio>
using namespace std;
int n,m,f[100001];
int main(){
	scanf("%d%d",&n,&m); f[0]=1; m++;
	for (int i=1;i<=m;i++) f[i]=i;
	for (int i=m+1;i<=n;i++) f[i]=(f[i-1]+f[i-m])%5000011;
	printf("%d",f[n]); 
    return 0;
}

JZOJ NO.2 最短路

分析

求n+C(n+m+1,m)


代码

#include <cstdio>
#define ull unsigned long long
using namespace std;
ull ans,ahs=1,n,m;
const ull mod=1e9+7;
ull qp(ull x,ull y){
	ull s=1;
	while (y){
		if (y&1) s=(s*x)%mod;
		y>>=1; x=(x*x)%mod;
	} return s;
}
int main(){
	scanf("%llu%llu",&n,&m);
	if (n<m) n^=m,m^=n,n^=m; ans=(n+m+1)%mod;
	for (ull i=2;i<=m;i++) ans=ans*(n+i)%mod,ahs=ahs*i%mod;
	ans=ans*qp(ahs,mod-2)%mod;//逆元
	printf("%llu",(ans%mod+n)%mod);
	return 0;
}

JZOJ NO.3 Magical GCD

分析

从左到右模拟O(T*N^2/gcd)必然会超时,所以就定义左右指针。相同的保左,右覆盖就好了。


代码

#include <cstdio>
#include <cctype> 
#define ull unsigned long long
using namespace std;
ull a[100001],g[100001],max; int t,n,r[100001],l[100001];
ull gcd(ull a,ull b){if (b) return gcd(b,a%b); else return a;}
ull in(){
	char c=getchar(); ull ans=0;
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
int main(){
	t=in();
	while (t--){
		max=0; n=in();
		for (int i=1;i<=n;i++){
			a[i]=in();
			g[i]=a[i]; l[i]=i-1; r[i]=i+1;
			//g[i]表示第i个数与n个数的最大公因数,l、r左右指针
		}
		for (int x=1;x<=n;x++)
		for (int i=1;i<=x;i=r[i]){
			g[i]=gcd(g[i],a[x]);
			ull c=g[i]*(x-i+1);
			max=(c>max)?c:max;
			if (g[i]==g[i-1]) //相同还需要重复运算吗
			r[l[i]]=r[i],l[r[i]]=l[i];
		}
		printf("%llu\n",max);
	}
	return 0;
} 

JZOJ NO.4 Multiset

题目

Alice 正在玩一个 multiset。最初,集合中只有一个元素 0。每一轮,集合中的每一个元素 x 都有 3 种可能的操作:
1、x 加上 1.即 x = x +1。
2、x 分裂成两个非负整数 y, z。即 x = y + z, 且 y >=0, z >= 0。
3、什么都不做。
注意,在一轮中每个元素只能选择一种操作。
Alice 已经玩了很久了, 但她并不知道自己已经玩了多少轮。 现在给出最终的集合,请你输出 Alice 最少玩的轮数。


分析

首先倒推一下,无非合并和-1。
所以就用桶模拟一下。


代码

#include <cstdio>
#include <cctype>
using namespace std;
unsigned short b[1000001]; int s,n,x,max;
int in(){
	char c=getchar(); int ans=0;
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
int main(){
	n=in(); for (int i=1;i<=n;i++) x=in(),b[x]++,max=(max>x)?max:x; s=b[0];//max一开始肯定最大的数
	for (int i=1;i<=max;i++) s=((s+1)>>1)+b[i];//0先合并
	while (s>1){s=(s+1)>>1;max++;}//合并非0
	printf("%d",max); return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值