2019.6.27 JZ DAY3总结

D A Y 3 DAY3 DAY3

今天洛谷打卡大吉,直接人生第一次A组200+。

T 1 T1 T1
二 叉 树 二叉树

Description
  在一个无穷的满二叉树中,有以下几个特点:
  (1) 每个节点都有两个儿子——左儿子和右儿子;
  (2) 如果一个节点的编号为X,则它的左儿子编号为2X,右儿子为2X+1;
  (3) 根节点编号为1。
  现在从根结点开始走,每一步有三种选择:走到左儿子、走到右儿子和停在原地。
  用字母“L”表示走到左儿子,“R”表示走到右儿子,“P”表示停在原地,用这三个字母组成的字符串表示一个明确的行走路线。
一个明确的行走路线的价值为最终到达节点的编号,例如LR的价值为5,而RPP的价值为3。
  我们用字符“L”、“R”、“P”和“”组成的字符串表示一组行走路线,其中“”可以是“L”、“R”、“P”中的任意一种,所有跟这个行走路线匹配的字符串都认为是可行的。
  例如L*R包含LLR、LRR和LPR。而**包含LL、LR、LP、RL、RR、RP、PL、PR和PP这9种路线。
  一组行走路线的价值等于所有匹配该模式的路线的价值之和。请你编程计算给定路线的价值。

Input
输入一个字符串表示一组行走路线,里面只含有“L”、“R”、“P”和“*”四种字符,长度不会超过10000。

Output
输出该路线的价值。

Sample Input
输入1:
P*P

输入2:
L*R

输入3:
**

输入4:
LLLLLRRRRRLLLLLRRRRRLLLLLRRRRRLLLLL

Sample Output
输出1:
6

输出2:
25

输出3:
33

输出4:
35400942560

Hint
【数据范围】
30%的数据满足路线中不含“ ∗ * ”;
50%的数据满足最多只有3个“*”。

浏览完所有题目后反手就来敲第一题,因为第一题的50分暴力分真的太诱人了。于是很快码出dfs的暴力,然后发现正解也是异常简单,如果为L则答案乘2,如果为R则答案乘2+cnt,如果为 ∗ * 则答案乘5+cnt。
cnt为3的x次方,x为 ∗ * 的出现次数。
然后发现答案可能超大,加一个高精度,然后自己模拟数据和暴力对拍,100分得手。

#include <cstdio>
#include <iostream>
using namespace std;

const int maxn = 11000;
string s;
int ans[maxn],cnt[maxn],len1,len2;

void work1(int a)
{
	int p = 0;
	for (int i = 1; i <= len1; i ++) 
	{
		ans[i] *= a;
		ans[i] += p;
		p = ans[i] / 10;
		ans[i] %= 10;
	}
	if (p) len1 ++,ans[len1] = p;
}

void work2(int a)
{
	int p = 0;
	for (int i = 1; i <= len2; i ++) 
	{
		cnt[i] *= a;
		cnt[i] += p;
		p = cnt[i] / 10;
		cnt[i] %= 10;
	}
	if (p) len2 ++,cnt[len2] = p;
}

void work3()
{
	for (int i = 1; i <= len2; i ++)
	{
		ans[i] += cnt[i];
		ans[i + 1] += ans[i] / 10;
		ans[i] %= 10;
	}
	if (ans[len1 + 1]) len1 ++;
}

int main()
{
	cin >> s;
	ans[1] = 1;
	len1 = 1;
	cnt[1] = 1;
	len2 = 1;
	for (int i = 0; s[i]; i ++)
	{
		if (s[i] == 'L') work1(2);
		if (s[i] == 'R') work1(2),work3();
		if (s[i] == '*') work1(5),work3(),work2(3);
	}
	for (int i = len1; i >= 1; i --) printf("%d",ans[i]);
	return 0;
}

T 2 T2 T2
猴 子 摘 桃 猴子摘桃

Description
  动物园内最受欢迎就是猴子了,因为它们除了能爬能跳外还会很多技能。其中A类猴子特别擅长爬树摘桃,而B类猴子擅长把桃子掰成两半。
  A类猴子有N只,编号为1到N,B类猴子有M只,编号为1到M。A类猴子中的第K只摘到第一个桃子需要花费A_k秒,此后每B_k秒就能摘到桃子;B类猴子中的第K只掰开第一个桃子需要花费C_k秒,此后每D_k秒就能掰开一个桃子。
  不幸的是,B类猴子非常具有侵略性,两种猴子不能同时待在场地内,因此,园长必须在A类猴子摘完所有桃子后立刻把它们带走,然后立刻让B类猴子进园;同样当B类猴子把所有桃子全部掰开后也不能待在场地内太久,因为它们之间也会发生冲突,所有园长将在B类猴子掰开所有桃子后立刻送走它们。
  园长带走猴子和猴子进园的速度非常快,时间忽略不计。
  Alice非常喜欢看B类猴子掰桃子,告诉你表演的总时间,但不知道一共有多少个桃子,请你帮Alice计算B类猴子进入动物园的时刻。
  
Input
  输入文件第一行包含一个整数T(1<=T<=1000000000),表示猴子表演的总时间。
  接下来一行包含一个整数N(1<=N<=100),表示A类猴子的数量。
  接下来N行,每行包含两个整数A_k和B_k(1<=A_k,B_k<=1000000000),描述A类每只猴子摘桃的速度。
  接下来一行包含一个整数M(1<=M<=100),表示B类猴子的数量。
  接下来M行,每行包含两个整数C_k和D_k(1<=C_k,D_k<=1000000000),描述B类每只猴子掰桃的速度。
 
Output
  输出两类猴子进园的时刻相差多少秒。

Sample Input
输入1:
12
1
3 1
1
5 1

输入2:
20
2
3 2
1 3
3
3 1
4 1
5 1

Sample Output
输出1:
5

输出2:
13

Hint
【样例说明】
  样例1中,树上有3个桃子:
  (1) A类猴子在3秒时摘下第一个桃子,在4秒时摘下第二个桃子,在5秒时摘下第三个桃子;
  (2) 在第5秒,园长把A类猴子带走,此时B类猴子进园;
  (3) B类猴子在10秒时掰开第一个桃子,在11秒时掰开第二个桃子,在第12秒时掰开第三个桃子;
  (4) 在12秒时园长进园带走B类猴子。

第一遍读完题本来是没什么思路的,感觉这是一个纯种的模拟,拿拿暴力分,今天的暴力分感觉拿到手软。但是稍作思考,这不就是一个简单的二分吗。然后就随便码了一下,70分,发现一个细节错误,改完100。考场切了第二题,100。(注意long long)
AC Code:

#include <cstdio>
#define ll long long
using namespace std;

const int maxn = 110;
ll T,n,m,a[maxn],b[maxn],c[maxn],d[maxn],l,r,ans;

ll sum1(ll p)
{
	ll x = 0;
	for (int i = 1; i <= n; i ++)
		if (p >= a[i]) x += (p - a[i]) / b[i] + 1ll;
	return x < 0 ? 0 : x;
}

ll sum2(ll p)
{
	ll x = 0;
	for (int i = 1; i <= m; i ++)
		if (p >= c[i]) x += (p - c[i]) / d[i] + 1ll;
	return x < 0 ? 0 : x;
}

int main()
{
	scanf("%lld",&T);
	scanf("%lld",&n);
	for (int i = 1; i <= n; i ++) scanf("%lld%lld",&a[i],&b[i]);
	scanf("%lld",&m);
	for (int i = 1; i <= m; i ++) scanf("%lld%lld",&c[i],&d[i]);
	l = 0ll,r = T;
	while (l < r)
	{
		ll mid = (l + r) / 2;
		ll x = sum1(mid),y = sum2(T - mid);
		if (x > y) r = mid; else ans = mid,l = mid + 1; 
	}
	printf("%lld\n",ans);
	return 0;
}

T 3 T3 T3
着 色 着色

Description
  Alice是一个奇怪的画家。她想对一副有N*N个像素点组成的画进行着色,N是2的幂(1,2,4,8,16等等)。每个像素点可以着成黑色或白色。
  Alice着色方案不是唯一的,她采用以下不确定的规则:
  •如果画作只有一个像素点,那可以直接着白色或黑色;
  •否则,把画平均分成四块,然后进行以下操作:
  (1) 选择一块全部着白色;
  (2) 选择一块全部着黑色;
  (3) 把剩下的两块当作是独立的画作并采用同样的方法进行着色。
  对于每一幅画作,Alice心目中已经有一个蓝图,接下来请你帮她采用上述方法着色,要求选择跟心目中的蓝图差异最小的着色方案,当然要遵循上述的着色规则,两幅图的差异是指对应位置颜色不相同的像素点的个数。

Input
  输入第一行包含整数N(1<=N<=512),表示画作的尺寸为N*N,N保证是2的幂。
  接下来N行每行包含N个0或1,描述Alice心目中的蓝图,0表示白色,1表示黑色。

Output
  第一行输出最小的差异是多少。

Sample Input
输入1:
4
0001
0001
0011
1110

输入2:
4
1111
1111
1111
1111

输入3:
8
01010001
10100011
01010111
10101111
01010111
10100011
01010001

Sample Output
输出1:
1
输出2:
6
输出3:
16

Hint
【数据范围】
  50%的数据N<=8

可惜了,考场时间不够,放了这道水题,只是打了一个正确性错误的贪心。考后正解是DP,有很多人用搜索也能过,然后我就用了爆搜,随意优化一下,就AC了。

#include <cstdio>
#include <cstring>
#include <iostream> 
#include <algorithm>
#define s1 x1,y1,midx,midy
#define s2 x1,midy + 1,midx,y2
#define s3 midx + 1,y1,x2,midy
#define s4 midx + 1,midy + 1,x2,y2
using namespace std;

const int maxn = 550;
struct Node{
	int sum,id;
} f[5];
int sum[maxn][maxn],n,ans;

int min(int a,int b) {return a < b ? a : b;}

int dfs(int x1,int y1,int x2,int y2)
{
	int ans = 550*550;
	if (x1 == x2) return 0;
	int midx = (x1 + x2) >> 1,midy = (y1 + y2) >> 1,sum1,sum2,sum3,sum4,sum5;
	sum1 = sum[midx][midy] - sum[x1 - 1][midy] - sum[midx][y1 - 1] + sum[x1 - 1][y1 - 1];
	sum2 = sum[midx][y2] - sum[midx][midy] - sum[x1 - 1][y2] + sum[x1 - 1][midy];
	sum3 = sum[x2][midy] - sum[x2][y1 - 1] - sum[midx][midy] + sum[midx][y1 - 1];
	sum4 = sum[x2][y2] - sum[x2][midy] - sum[midx][y2] + sum[midx][midy];
	sum5 = (x2 - x1 + 1) * (y2 - y1 + 1) / 4;
	int a1 = dfs(s1),a2 = dfs(s2),a3 = dfs(s3),a4 = dfs(s4);
	if (sum1 + sum5 - sum2 < sum2 + sum5 - sum1) ans = min(ans,sum1 + sum5 - sum2 + a3 + a4); else ans = min(ans,sum2 + sum5 - sum1 + a3 + a4);
	if (sum1 + sum5 - sum3 < sum3 + sum5 - sum1) ans = min(ans,sum1 + sum5 - sum3 + a2 + a4); else ans = min(ans,sum3 + sum5 - sum1 + a2 + a4);
	if (sum1 + sum5 - sum4 < sum4 + sum5 - sum1) ans = min(ans,sum1 + sum5 - sum4 + a2 + a3); else ans = min(ans,sum4 + sum5 - sum1 + a2 + a3);
	if (sum2 + sum5 - sum3 < sum3 + sum5 - sum2) ans = min(ans,sum2 + sum5 - sum3 + a1 + a4); else ans = min(ans,sum3 + sum5 - sum2 + a1 + a4);
	if (sum2 + sum5 - sum4 < sum4 + sum5 - sum2) ans = min(ans,sum2 + sum5 - sum4 + a1 + a3); else ans = min(ans,sum4 + sum5 - sum2 + a1 + a3);
	if (sum3 + sum5 - sum4 < sum4 + sum5 - sum3) ans = min(ans,sum3 + sum5 - sum4 + a1 + a2); else ans = min(ans,sum4 + sum5 - sum3 + a1 + a2);
	return ans;
}

int main()
{
	scanf("%d",&n);
	sum[0][0] = 0;
	for (int i = 1; i <= n; i ++)
	{
		string s;
		cin >> s;
		for(int j = 1; j <= s.length(); j ++) sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + s[j - 1] - '0';
	}
	printf("%d",dfs(1,1,n,n));
	return 0;

考试状态有进步,100 + 100 + 30 = 230pts,排名也有进步rank9,还要努力变强。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值