牛客暑期多校解题报告: 2

J

给定一个数列 a 1 , a 2 , . . . , a n a_1, a_2, ..., a_n a1,a2,...,an, 求一个等差数列 a 1 ′ , a 2 ′ , . . . , a n ′ a_1^{'}, a_2^{'},..., a_n^{'} a1,a2,...,an,使得 ∑ i = 1 n ( a i − a i ′ ) 2 \sum_{i=1}^{n}(a_i-a_i^{'})^2 i=1n(aiai)2, 最小,输出这个最小值。
线性回归,找出一条直线和这组点的竖直距离的平方和最短。
假设有一堆点 ( x i , y i ) (x_i, y_i) (xi,yi),求一条直线 y ′ = A x + b y^{'}=Ax+b y=Ax+b使得 ∑ i = 1 n ( y i − y ′ ( x i ) ) 2 \sum_{i=1}^{n}(y_i-y^{'}(x_i))^2 i=1n(yiy(xi))2最小
x ˉ = ( ∑ i = 1 n x i ) / n , y ˉ = ( ∑ i = 1 n y i ) / n \bar{x}=(\sum_{i=1}^{n}x_i)/n, \bar{y}=(\sum_{i=1}^{n}y_i)/n xˉ=(i=1nxi)/n,yˉ=(i=1nyi)/n
则有
A = ∑ i = 1 n x i y i − n x ˉ y ˉ ∑ i = 1 n x i 2 − n ( x ˉ ) 2 A=\frac{\sum_{i=1}^{n}x_iy_i - n\bar{x}\bar{y}}{\sum_{i=1}^{n}x_i^2-n(\bar{x})^2}\\ A=i=1nxi2n(xˉ)2i=1nxiyinxˉyˉ
B = y ˉ − A x ˉ B=\bar{y}-A\bar{x} B=yˉAxˉ
按照这个结论带入就可以算出答案了。P.S: 线性回归是我在网上找的捏,自己写挂了🫠

#include <cstdio>
#include <algorithm>
#include <cctype>
#include <cmath>

using namespace std;
const int maxn = 1e5+5;
int arr[maxn];

namespace GTI
{
    char gc(void)
       {
        const int S = 1 << 16;
        static char buf[S], *s = buf, *t = buf;
        if (s == t) t = buf + fread(s = buf, 1, S, stdin);
        if (s == t) return EOF;
        return *s++;
    }
    int gti(void)
       {
        int a = 0, b = 1, c = gc();
        for (; !isdigit(c); c = gc()) b ^= (c == '-');
        for (; isdigit(c); c = gc()) a = a * 10 + c - '0';
        return b ? a : -a;
    }
}
using GTI::gti;

int main(void)
{
    /* freopen("in.txt", "r", stdin); */
    int T;
    scanf("%d", &T);
    while(T--) {
        int n = gti();
        long double a, b, b1, mxy, sum_x, sum_y, lxy, xiSubSqr;
        a = b = b1 = mxy = sum_x = sum_y = lxy = xiSubSqr = 0.0;

        for(int i = 1; i <= n; ++i) {
            sum_x += i;
            arr[i] = gti();
            sum_y += arr[i];
        }

        long double x_avg = sum_x / n;
        long double y_avg = sum_y / n;

        for(int i = 1; i <= n; ++i) {
            lxy += (i-x_avg) * (arr[i]-y_avg);
            xiSubSqr += (i-x_avg) * (i-x_avg);
        }

        b = lxy/xiSubSqr;
        a = y_avg - b * x_avg;

        long double ans = 0;

        for(int i = 1; i <= n; ++i) {
            ans += pow(1.0*b*i+a-arr[i], 2);
        }

        printf("%.15Lf\n", ans);
    }
    return 0;
}

K

给定一个长度为n的括号序列a,a是另一个长度为m的合法括号序列b的子序列,给定a,求可能的b的数量。
合法括号序列 A ::= empty | (A) | AB
dp(i, j, k) 代表b的前i个最多匹配a的前j个,剩下k个左括号未匹配。
考虑状态转移
已知状态dp(i, j, k),如果a[j+1]==‘(’, 则向b添加一个’(', 状态转移到dp(i+1, j+1, k+1)其他转移方式同理

#include <cstring>
#include <cmath>
#include <cstdio>

using namespace std;
typedef long long ll;
const int maxn = 205;
const int mod = 1e9+7;

ll dp[maxn][maxn][maxn];
int min(int a, int b) { return a>b?b:a; }

int main(void)
{
    int T, n, m;
    char s[300];
    scanf("%d", &T);

    while(T--) {
        scanf("%d%d", &n, &m);
        scanf(" %s", s);
        for(int i = 1; i <= m; ++i) {
            for(int j = 0; j <= min(n, i); ++j) {
                for(int k = 0; k <= i; ++k) {
                    dp[i][j][k] = 0;
                }
            }
        }
        dp[0][0][0] = 1;
        for(int i = 1; i <= m; ++i) {
            for(int j = 0; j <= min(n, i); ++j) {
                for(int k = 0; k <= i; ++k) {
                    if(j && s[j-1] == '(') {
                        dp[i][j][k] = (dp[i][j][k]+dp[i-1][j-1][k-1])%mod;
                    }
                    if(j && s[j-1] == ')') {
                        dp[i][j][k] = (dp[i][j][k] + dp[i-1][j-1][k+1]) % mod;
                    }
                    if(j == 0 || s[j-1] == '(') {
                        dp[i][j][k] = (dp[i][j][k] + dp[i-1][j][k+1]) % mod;
                    }
                    if((j==0 || s[j-1] == ')') && k) {
                        dp[i][j][k] = (dp[i][j][k] + dp[i-1][j][k-1]) % mod;
                    }
                }
            }
        }
        printf("%lld\n", dp[m][n][0]);
    }
    return 0;
}

L

给出一个游戏,这个游戏的有多张有向图,编号分别从1到n。每张图上都有1到m个节点。玩家从第一张图开始出发,在每张图上可以选择移动一步,也可以选择不移动;假设操作后玩家所在的节点数是i,则他转移到下一张图的节点i。要求求出到达节点m的最小的使用图的数量。
考虑使用动态规划解决问题,因为题目内存的限制,所以要用滚动数组来优化空间

#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 2010;

// dp[i][j] 代表在第i个世界到达节点j所需的最小步数
int d[maxn], dd[maxn], l, m, n;

int main(void)
{
    scanf("%d%d", &n, &m);
    memset(d, inf, sizeof d);
    d[1] = 1;

    while(n--) {
        scanf("%d", &l);

        for(int i = 1; i <= m; ++i) {  // 依次更新到达第i个节点的距离
            if(i > 1 && i < m && d[i] != inf)
                ++d[i];
        }

        memcpy(dd, d, sizeof d);

        while(l--) {  // dp[i+1][j] = min(dp[i][j]+1, min(dp[i][u]+1)), 其中u->j有一条路
            int x, y;
            scanf("%d%d", &x, &y);
            dd[y] = min(dd[y], d[x]);
        }

        memcpy(d, dd, sizeof d);
    }

    printf("%d\n", d[m] == inf ? -1 : d[m]);

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值