2019暑期组队排位总结
- 2019牛客暑期多校(第一场)
- 2019牛客暑期多校(第二场)
- 2018 ICPC Asia Singapore Regional
- 2019牛客暑期多校(第三场)
- 2019牛客暑期多校(第四场)
- 2019牛客暑期多校(第五场)
- 2018-2019, ICPC, Asia Yokohama Regional Contest 2018
- 2018-2019 ACM-ICPC, Asia Seoul Regional Contest
- 2019牛客暑期多校(第六场)
- 2019牛客暑期多校(第七场)
- 2019牛客暑期多校(第八场)
- 2017-2018 ACM-ICPC, Asia Tsukuba Regional Contest
- 2018-2019 ACM-ICPC Southeastern European Regional Programming Contest
- 2018 ICPC East-Central NA Regional Contest
- 2018 ACM-ICPC North Central North America Regional Contest
- 2016 ICPC Mid-Central USA Region
- 2018 CCPC吉林赛区
- 2018 Rocky Mountain Regional Contest
- 2019牛客暑期多校(第九场)
- 2019牛客暑期多校(第十场)
Wiki:戳这里
我还是习惯性在博客也开一篇总结方便看吧哈哈哈哈
2019牛客暑期多校(第一场)
problem J
题意:给你两个分数x/a,y/b,要你比较他们大小。分子范围为1e18,分母范围为1e9。
题解:直接交叉相乘会爆ll,所以先把两个数的整数部分求出来作比较,如果整数部分一样,再把分子%分母,这样两个分数交叉相乘就不会爆ll,可以比较了。
problem A
题意:两个数组定义为相等的,当且仅当从两个数组中任选一个区间[l,r],他们的最小值的下标是一样的,给你两个数组u和v,问你最大的下标p,使得1到p中任选一个区间,他们的最小值下标是一样的。
证明:假设遍历到第i个元素,也就是前i-1个元素都是符合条件的,那么我们需要考虑的新区间就是以第i个元素为右端点的所有区间,现在我们考虑以第i个元素为最小值的区间最左能延伸到哪里,如果两个数组最左能延伸到的位置,即栈大小是一样的,就说明是符合条件的。
题解:两个数组分别用一个单调递增的栈维护,当且仅当遍历到第i个元素,两个栈的size一样,ans = p,否则,直接break。
代码:戳这里
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
int x[maxn],y[maxn];
int main()
{
int n;
while(~scanf("%d",&n))
{
for(int i=1; i<=n; i++)
{
scanf("%d",&x[i]);
}
for(int i=1; i<=n; i++)
{
scanf("%d",&y[i]);
}
stack<int> a,b;
int ans = 1;
for(int i=1; i<=n; i++)
{
while(!a.empty() && x[i] < a.top())
{
a.pop();
}
a.push(x[i]);
while(!b.empty() && y[i] < b.top())
{
b.pop();
}
b.push(y[i]);
if(a.size() != b.size())
break;
else
ans = i;
}
printf("%d\n",ans);
}
}
problem E
题意:一个2*(n+m)长度的只包含“A”“B”的序列,可以分解成n+m个子序列,其中有n个“AB”,m个“BA”,给你n和m,问你符合条件的序列有多少个。
题解:对于一个序列从前往后遍历过去,遇到一个“A”,肯定会优先把它当成“AB”的“A”,再考虑它是“BA”的“A”,遇到一个“B”同理。那么我们可以有dp[x][y]表示一共有x个“A”,y个“B”,当x或y至少有一个为0,此时方案数只有1。根据之前的贪心策略,任一时刻不同时满足y-x<=m和x-y<=n的话,方案数为0。这样,一个记忆化搜索的dp就很好写出来了。
代码:戳这里
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <stack>
using namespace std;
typedef long long ll;
const int maxn = 2005;
const int mod = 1e9+7;
int n,m;
ll dp[maxn][maxn];
ll solve(int x,int y)
{
if(y - x > m || x - y > n)
return 0;
if(x == 0 || y == 0)
return 1;
if(dp[x][y])
return dp[x][y];
dp[x][y] = solve(x-1,y) + solve(x,y-1);
dp[x][y] %= mod;
return dp[x][y];
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i=0; i<=n+m; i++)
{
for(int j=0; j<=n+m; j++)
{
dp[i][j] = 0;
}
}
printf("%lld\n",solve(n+m,n+m));
}
}
2019牛客暑期多校(第二场)
problem F
题意:给定一个N*N矩阵,令第i行j列为a[i][j],在此可理解为i和j的价值。题目要求把1–>N人分成两组,且当i和j不同组时,价值生效,否则价值为0。求分组后的最大总价值。 !!! 1<=N<=14 !!!
题解:范围不大,可暴力。 dfs模拟分组。对于当前的i,若数组A人数不够,进A组,并更新当前总价值(即加上i和B组所有人的价值)进入下一次dfs。对于B组操作也一样。
problem H
题意:给你一个只包含0和1的n×m大小的矩阵,问你第二大的全为1的矩形有多大。(不严格第二大)
题解:每个矩阵的大小由长和宽决定,矩形的长对应原矩阵中每一行最多有多少个元素,他们向上扩展的连续“1”的数量一样,矩形的宽对应向上扩展的连续“1”的数量。我们从第一行开始枚举,一开始先更新该行所有元素向上扩展最多有多少个连续“1”,设为c[j]数组,然后用一个单调递增的栈维护该行的c[j]数组,找出该行每个元素以自己为最小值,向左向右分别最远扩展到哪里,这里就有l[i],r[i]数组,此时最大的矩形面积应为(r[i]-l[i]+1)* c[j],第二小的值是max((r[i]-l[i])* c[j],(r[i]-l[i]+1) * (c[j] - 1)),然后不断更新最大值和第二大值,最后的第二大值就是答案。
代码:https://pastebin.ubuntu.com/p/BHfz5g4sPz/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
using namespace std;
const int maxn = 1005;
char a[maxn][maxn];
int c[maxn],l[maxn],r[maxn];
void update(int &mx,int &mmx,int x)
{
if(x <= mmx)
return;
if(x <= mx)
{
mmx = x;
return;
}
mmx = mx;
mx = x;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
int mx = 0,mmx = 0;
for(int i=