2019牛客多校第一场
A:Equivalent Prefixes(单调栈)
- 题意:注意是每个子区间都要满足
- 可以发现必须要有单调性,想到要同增同减
- 然后找到一个满足同增同减,但是不符合题意的反例:
- 1 3 2
- 1 3 0
- 然后发现必须要维护一个以当前点结尾的最长上升子序列长度相同
- 如果不同就break
- 就想到单调栈 不过我不会严格证明,比赛的时候找不到反例
#include <bits/stdc++.h> #define ll long long using namespace std; const ll mod = 1e9 + 7; const int N = 1e5 + 10; int a[N], b[N]; int q1[N], q2[N]; int main() { int n; while (scanf("%d", &n) != EOF) { for (int i = 1; i <= n; i++)scanf("%d", &a[i]); for (int i = 1; i <= n; i++)scanf("%d", &b[i]); int l1 = 0, r1 = 0, l2 = 0, r2 = 0; int ans = 1; for (int i = 1; i <= n; i++) { while (l1 <= r1 && q1[r1] > a[i]) { r1--; } q1[++r1] = a[i]; while (l2 <= r2 && q2[r2] > b[i]) { r2--; } q2[++r2] = b[i]; if ((r1 - l1) == (r2 - l2))ans = i; else break; } printf("%d\n", ans); } return 0; }
B: Integration(数学)
- 题意:求那个积分
- 裂项
- 把乘换成减,两项两项地换
- 复杂度
- 积分的可加性
- 记录系数,最后再乘以积分的值
- 代码
#include <bits/stdc++.h> #define ll long long using namespace std; const int mod = 1e9 + 7; ll s[1010]; ll pre[1010]; ll qpow(ll a, ll n) { ll res = 1; a %= mod; while (n) { if (n & 1) res = res * a % mod; a = a * a % mod; n >>= 1; } return res; } int main() { int n; while (scanf("%d", &n) != EOF) { for (int i = 1; i <= n; ++i) scanf("%lld", &s[i]), pre[i] = 0; pre[1] = 1; for (int i = 2; i <= n; ++i) { for (int j = 1; j < i; ++j) { pre[j] = (pre[j] * qpow(((s[i] * s[i] % mod - s[j] * s[j] % mod)%mod + mod) % mod,mod-2)+mod)% mod; pre[i] = ((pre[i] - pre[j]) % mod + mod) % mod; } } ll ans = 0; for (int i = 1; i <= n; ++i) { ans = ((ans + pre[i] * qpow(s[i] * 2LL, mod - 2) % mod+mod)%mod+mod) % mod; } printf("%lld\n", ans); } return 0; }
C:Euclidean Distance(数学+贪心)
题意:题意比较明显,P的和是1,然后给出A,求那个最小值.
数学:题解的证明就看懂第一行
贪心:先把P转换一下,去a的分母让P的和为m
可以看这个大牛的博客:
https://blog.nowcoder.net/n/1539da6d6d6e47a6998b5c6f5bba2167
代码:
#include <bits/stdc++.h> #define ll long long using namespace std; const int mod = 1e9 + 7; const int maxn = 1e4 + 10; ll s[maxn]; ll pre[maxn]; int main() { int n, m; while (scanf("%d%d", &n, &m) != EOF) { for (int i = 1; i <= n; ++i) { scanf("%lld", &s[i]); } sort(s + 1, s + 1 + n); reverse(s + 1, s + 1 + n); pre[0] = -m; for (int i = 1; i <= n; ++i) { pre[i] = pre[i - 1] + s[i]; } ll pos = n; for (ll i = 0; i < n; ++i) { if (pre[i] > s[i + 1] * i) { pos = i; break; } } ll ansa = pre[pos] * pre[pos] * pos; ll ansb = pos * pos; for (ll i = pos + 1; i <= n; ++i) { ansa += s[i] * s[i] * ansb; } ansb *= (m * m); ll g = __gcd(ansa, ansb); ansa /= g; ansb /= g; if (ansb == 1) { printf("%lld\n", ansa); } else { printf("%lld/%lld\n", ansa, ansb); } } return 0; }
E:ABBA(贪心+DP)
题意:就是有个"AB",个"BA",问能结合成多少个序列.这个要求是AB和BA的顺序不变,即A和B的相对位置不变.我们要讨论一下什么才是合法的状态.
贪心:
- 假设只有个AB,合法情况是每个B前面要有个A
- 假设除了有AB,还有个BA,那每个B前面可以有超过个A,但是第一个B前面还是要有个A.否则就会使BA类型的某个B后面没A.
- B与后面的A可以构成BA,相当于抵消了一个A,那下一个B前面就只需要有未被抵消的A.
- 所以A-B小于等于是合法的.当A-B等于,意味着最后一个只能是A,因为如果最后一个是B,那B前面就有个未被抵消的A.
- A前面有多少个B也是同理.
DP
,代表A的个数,代表B的个数.值代表合法方案.
初始化,按照上述前缀的限定
不考虑那么多,可以简单得出
但是要排除非法的情况
- 和 是合法情况
- 注意和和的情况
- 代码
#include <bits/stdc++.h> #define ll long long using namespace std; const ll mod = 1e9 + 7; const ll N = 1e5 + 10; ll dp[2010][2010]; int main() { ll n, m; while (scanf("%lld%lld", &n, &m) != EOF) { ll cnt = (n + m); for (int i = 0; i <= cnt; i++) for (int j = 0; j <= cnt; j++) dp[i][j] = 0; for (ll i = 0; i <= cnt; i++) { dp[i][0] = dp[0][i] = 1; } for (ll i = 1; i <= cnt; i++) { for (ll j = 1; j <= cnt; j++) { if (i == j) { if (n) dp[i][j] = (dp[i][j] + dp[i][j - 1]) % mod; if (m) dp[i][j] = (dp[i][j] + dp[i - 1][j]) % mod; } else if (j > i) { if (j - i < m) dp[i][j] = ((dp[i][j] + dp[i - 1][j]) % mod + dp[i][j - 1]) % mod; else if (j - i == m) dp[i][j] = (dp[i][j] + dp[i][j - 1]) % mod; } else if (i > j) { if (i - j < n) dp[i][j] = ((dp[i][j] + dp[i - 1][j]) % mod + dp[i][j - 1]) % mod; if (i - j == n) dp[i][j] = (dp[i][j] + dp[i - 1][j]) % mod; } //cout<<i<<" "<<j<<" "<<dp[i][j]<<endl; } } printf("%lld\n", dp[cnt][cnt] % mod); } return 0;
F:Random Point in Triangle(期望+随机+叉积)
参考了一下大牛的博客
首先我们得出当一个点P随机落在三角形内部,新三角形BPC的高的期望为
证明如下:(字丑勿怪)
得到了这个,那就好办了,就变成了简单几何问题.
剩下的可以看大佬的博客,我就不赘述了.
#include <bits/stdc++.h> #define ll long long using namespace std; const ll mod = 1e9 + 7; const ll N = 1e5 + 10; int main() { ll x1, y1, x2, y2, x3, y3; while (~scanf("%lld%lld%lld%lld%lld%lld", &x1, &y1, &x2, &y2, &x3, &y3)) { ll ans = 11; ll cnt = abs(x1 * y2 + x2 * y3 + x3 * y1 - x1 * y3 - x2 * y1 - x3 * y2); ans = ans * cnt; printf("%lld\n", ans); } return 0; }
Fraction Comparision(大数+JAVA)
居然不会JAVA的多组输入,JAVA白考98了…..
一开始用了nextline 一直RE.
import java.math.*; import java.util.*; public class Main { static BigInteger ans,m; static BigInteger[] arr; static int n; public static void main(String []args){ Scanner cin = new Scanner(System.in); //Long x,a,y,b; BigInteger x,a,y,b; while(cin.hasNextBigInteger()){ x=cin.nextBigInteger(); a=cin.nextBigInteger(); y=cin.nextBigInteger(); b=cin.nextBigInteger(); int s=b.multiply(x).compareTo(a.multiply(y)); if(s>0){ System.out.println(">"); }else if(s==0){ System.out.println("="); }else{ System.out.println("<"); } } } }