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(ai−ai′)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(yi−y′(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=1nxi2−n(xˉ)2∑i=1nxiyi−nxˉ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;
}