目錄
總結:
我好菜呀,這場該 AK 的...
Stoichiometry
一.題目大意:
化學方程式配平
二.分析:
直接高斯消元,由於題目說含有唯一最小解,說明有且只有一個自由元,枚舉自由元的值,使得各系數爲整數即可.
三.代碼實現:
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
int len;
struct node
{
int sgn, n;
string ele[20];
int num[20];
}s[20];
int cnt;
map <string, int> id;
double a[10][10];
int x[10];
void read()
{
while(cin >> s[len].sgn >> s[len].n && s[len].sgn && s[len].n)
{
for(int i = 0; i < s[len].n; ++i)
{
cin >> s[len].ele[i] >> s[len].num[i];
if(!id.count(s[len].ele[i]))
id[s[len].ele[i]] = cnt++;
}
++len;
}
}
void build()
{
for(int i = 0; i < len; ++i)
{
for(int j = 0; j < s[i].n; ++j)
{
a[id[s[i].ele[j]]][i] += s[i].num[j] * s[i].sgn;
}
}
}
int gauss()
{
int c, r;
for(c = 0, r = 0; c < len; ++c)
{
int t = r;
for(int i = r; i < cnt; ++i)
{
if(fabs(a[i][c]) > fabs(a[t][c])) t = i;
}
if(fabs(a[t][c]) < eps) continue;
for(int i = c; i < len; ++i) swap(a[t][i], a[r][i]);
for(int i = len - 1; i >= c; --i) a[r][i] /= a[r][c];
for(int i = 0; i < cnt; ++i)
{
if(i == r) continue;
if(fabs(a[i][c]) > eps)
{
for(int j = len - 1; j >= c; --j)
{
a[i][j] -= a[r][j] * a[i][c];
}
}
}
++r;
}
}
bool check(int x)
{
double s;
for(int i = 0; i < len; ++i)
{
s = -a[i][len - 1] * x;
if(abs(int(s + eps) - s) > eps)
return 0;
}
return 1;
}
void work()
{
for(int i = 1; ; ++i)
{
if(check(i))
{
for(int j = 0; j < len - 1; ++j)
printf("%d ", (int)(-a[j][len - 1] * i + eps));
printf("%d\n", i);
return;
}
}
}
int main()
{
read();
build();
gauss();
work();
return 0;
}
Smooth Array
一.題目大意:
長度爲 n 的數組 a,現可以修改每個數爲任意值,使得每 k 個連續的數的和爲 s,求最小修改次數.
二.分析:
很容易得知 a[i] == a[i + j * k].
於是可以把數分爲 k 組,問題轉化成使得組內元素相等,每組元素加和爲 s 的最小修改次數.
很明顯的 DP,設 dp[i][j] 表示考慮了前 i 組,且前 i 組元素加和爲 s 的最大不修改次數.
最終答案即爲 n - dp[k - 1][s].
狀態計算很簡單,懶得講了.
三.代碼實現:
#include <bits/stdc++.h>
using namespace std;
const int M = (int)5e3;
const int inf = 0x3f3f3f3f;
int a[M + 5];
int cnt[M + 5];
vector <int> v;
int dp[2][M + 5];
int main()
{
int n, k, s;
scanf("%d %d %d", &n, &k, &s);
for(int i = 0; i < n; ++i)
scanf("%d", &a[i]);
memset(dp, -inf, sizeof(dp));
for(int i = 0; i < k; ++i)
{
v.clear();
memset(cnt, 0, sizeof(cnt));
for(int j = 0; i + j * k < n; ++j)
{
if(cnt[a[i + j * k]] == 0)
{
v.push_back(a[i + j * k]);
}
++cnt[a[i + j * k]];
}
if(i == 0)
{
for(int j = 0; j <= s; ++j)
dp[i & 1][j] = cnt[j];
}
else
{
int mx = -inf;
for(int j = 0; j <= s; ++j)
{
dp[i & 1][j] = -inf;
for(auto x: v)
{
if(j >= x)
dp[i & 1][j] = max(dp[i & 1][j], dp[i - 1 & 1][j - x] + cnt[x]);
}
mx = max(mx, dp[i - 1 & 1][j]);
dp[i & 1][j] = max(dp[i & 1][j], mx);
}
}
}
printf("%d\n", n - dp[k - 1 & 1][s]);
return 0;
}