A. Serval and Bus
手速题,题意给你n个车次和到达时间,帮S同学坐上最早的车。车有第一次到达时间和间隔时间。
分析:很简单,只需让所有车次都变成达到时间之后的,然后挑选最早的那个即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 110;
int t, n, x[maxn];
struct nod
{
int s, d, re;
} m[maxn];
bool cmp(nod x, nod y)
{
return x.s < y.s;
}
int main()
{
scanf("%d%d", &n, &t);
int flag = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d%d", &m[i].s, &m[i].d);
m[i].re = i;
while(m[i].s < t)
m[i].s += m[i].d;
}
sort(m + 1, m + n + 1, cmp);
printf("%d\n", m[1].re);
return 0;
}
B - Serval and Toy Bricks CodeForces - 1153B
简单思维题,简单到没有思维含量,给你正面看的高度和侧面看的高度,然后让你给出柱体摆放的可能情况。
因为我们看到的只能是最高高度,因而可能情况可以简单的构造为正面和侧面看到的最小值。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 110;
int n, m, h, a[maxn], b[maxn], mp[maxn][maxn];
int main()
{
scanf("%d%d%d", &n, &m, &h);
for(int i = 1; i <= m; i++) scanf("%d", &a[i]);
for(int i = 1; i <= n; i++) scanf("%d", &b[i]);
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
scanf("%d", &mp[i][j]);
if(mp[i][j]) mp[i][j] = min(a[j], b[i]);
}
}
for(int i = 1; i <= n; i++)
{
printf("%d", mp[i][1]);
for(int j = 2; j <= m; j++)
{
printf(" %d", mp[i][j]);
}
printf("\n");
}
return 0;
}
C. Serval and Parenthesis Sequence
有点难度的字符串贪心题。读题难度++,跑偏++;
题意:让你把问号用‘(’或‘)’补全,而且要求不能有前缀括号。写出一个可能情况。
分析贪心我们可以尽可能把前面凑齐n/2 个‘(’然后剩下的补成‘)’最后看看是否合适即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 10;
int n;
char ch[maxn];
int main()
{
scanf("%d", &n);
scanf("%s", ch + 1);
if(n % 2) printf(":(\n");
else
{
int a = 0, flag = 0;
for(int i = 1; i <= n; i++)
if(ch[i] == '(') a++;
for(int i = 1; i <= n; i++)
if(ch[i] == '?' && a < n / 2) ch[i] = '(', a++;
for(int i = 1; i <= n; i++)
if(ch[i] == '?') ch[i] = ')';
a = 0;
for(int i = 1; i <= n; i++)
{
if(ch[i] == '(') a++;
else
{
a--;
if((a == 0 && i != n)|| a < 0) flag = 1;
}
}
if(flag || a) printf(":(\n");
else cout << ch + 1 << '\n';
}
return 0;
}
D. Serval and Rooted Tree(DP)
这个有难度了,嘤。
题意,给你一群数,然后他们都是有一个状态0/1,0说明它取最小的子树的值,1取最大的。非叶子节点的值由子节点决定,叶子结点的值从1 - n。
分析;由题意我们可以看出叶子结点的数目决定编号的大小,最大值则为cnt(叶子结点数)+ 1 - dp[1]。
状态转移方程
x == 0 dp[t] += dp[vec[t][i]]; // 0取最小,因而把所有子节点加起来
x == 1 dp[t] = min(dp[t], dp[vec[t][i]]); // 1取最大,只要有了最小值减去极为最大值
#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 10;
vector <int> vec[maxn];
int n, a[maxn], dp[maxn], cnt, vis[maxn];
map <int, int> mp;
void dfs(int t)
{
if(vec[t].size() == 0)
{
dp[t] = 1;
return;
}
if(a[t] == 1)
{
dp[t] = 0x3f3f3f3f;
for(int i = 0; i < vec[t].size(); i++)
{
dfs(vec[t][i]);
dp[t] = min(dp[t], dp[vec[t][i]]); // == 1的情况
}
}
else
{
for(int i = 0; i < vec[t].size(); i++)
{
dfs(vec[t][i]);
dp[t] += dp[vec[t][i]];
}
}
return ;
}
int main()
{
scanf("%d", &n);
cnt = n;
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
for(int i = 2; i <= n; i++)
{
int fa;
scanf("%d", &fa);
if(!vis[fa]) cnt--, vis[fa] = 1; // 统计叶子结点数目
vec[fa].push_back(i);
}
dfs(1);
printf("%d\n", cnt + 1 - dp[1]);
}