A题
正解:笛卡尔树
师兄做法:二分/线段树, 首先二分答案,判断答案是否合法时,先找整个区间的最小值是否索引相同,再找最小值分成的两个小区间是否符合这样一直分下去。。。(写线段树好麻烦的说)
我做的暴力:从左到右,对于第i行查找后面第一个比该行数字小的下标,相同就继续第i+1行,不相同则说明后面的那几行不满足条件删去
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int n,cnt;
int a[maxn],b[maxn];
int main()
{
while(~scanf("%d",&n))
{
for(int i = 0;i < n; ++i) scanf("%d",&a[i]);
for(int i = 0;i < n; ++i) scanf("%d",&b[i]);
cnt = n - 1;
for(int i = 0;i <= cnt; ++i)
{
for(int j = i + 1;j <= cnt; ++j)
{
int f = 0;
if(a[i] > a[j]) f++;
if(b[i] > b[j]) f++;
if(f == 2) break;
if(f == 1)
{
cnt = j - 1;
break;
}
}
}
printf("%d\n",cnt + 1);
}
return 0;
}
B题
贼坑啊,开始就没看懂样例啥意思。。。后来跟着题解推ci推了n久也。。。没推出来(只能背过)
然后发现还有个取倒数再取模(有人写的递推法求逆元)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int p = 1e9 + 7;
ll a[1005];
int n;
ll inv(ll b) //递推法求逆元
{
if(b == 1) return 1;
return p - p / b * inv(p % b) % p;
}
int main()
{
while(~scanf("%d",&n))
{
for(int i = 1;i <= n;i++) scanf("%lld",&a[i]);
ll ans = 0;
for(int i = 1;i <= n;i++)
{
ll res = 1;
for(int j = 1;j <= n;j++)
{
if(i == j) continue;
res = (res * (a[j] * a[j] % p - a[i] * a[i] % p + p) % p) % p;
}
res = res * 2 * a[i] % p;
res = inv(res);
ans = (res + ans) % p;
}
printf("%lld\n",ans);
}
return 0;
}
E题
这个题首先会想到求方案数,动态规划或者组合数之类的
不过确实不好推情况太多了
最后借鉴题解
令f[i][j]为有i个A,j个B的合法方案数
当有i - j < n时,说明还没有凑齐n个AB,要满足有n个AB,A在前面的数量还不够,所以后面可以放A
f[i + 1][j] = f[i][j] + f[i + 1][j];
当有j - i < m时,说明还没有凑齐m个BA,要满足有m个BA,B在前面的数量还不够,所以后面可以放B
f[i][j + 1] = f[i][j] + f[i][j + 1];
/*
令f[i][j]为有i个A,j个B的合法方案数
当有i - j < n时,说明还没有凑齐n个AB,要满足有n个AB,A在前面的数量还不够,所以后面可以放A
f[i + 1][j] = f[i][j] + f[i + 1][j];
当有j - i < m时,说明还没有凑齐m个BA,要满足有m个BA,B在前面的数量还不够,所以后面可以放B
f[i][j + 1] = f[i][j] + f[i][j + 1];
*/
#include<bits/stdc++.h>
using namespace std;
const int p = 1e9 + 7;
int n,m;
int f[2010][2010];
int main()
{
while(~scanf("%d%d",&n,&m) && (n + m))
{
for(int i = 0;i <= n + m; ++i)
for(int j = 0;j <= n + m; ++j)
f[i][j] = 0;
f[0][0] = 1;
for(int i = 0;i <= n + m; ++i)
for(int j = 0;j <= n + m; ++j)
{
if(i - j < n) f[i + 1][j] = (f[i][j] + f[i + 1][j]) % p;
if(j - i < m) f[i][j + 1] = (f[i][j] + f[i][j + 1]) % p;
}
printf("%d\n",f[n + m][n + m]);
}
return 0;
}
F题
瞎猜的,没想到猜对了hhh
证明挺麻烦的,几何法和积分都能做(反正我都不会做。。。。)