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,还要努力变强。