昨天写课内作业鸽了一整天,该骂
文章目录
CF 577B Modulo Sum
好狡诈的题。。。本来想到dp但是一看数据范围不太能规划起来,看了题解原来需要先优化一下,如果n>m的话,前缀和取余的原理,一定会有两个前缀和取余的数相等,也就一定有答案,然后n<=m的情况再dp,dp[i][j]
表示前 i 个数能不能组成 j 的倍数,转移时如果 dp[i - 1][j]
是true,那么选第 i 个数的话,就是 dp[i][(j + a[i]) % m]
为true,不选就是 dp[i][j] = true
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<PII, int> PIII;
const int N = (1 << 19);
const int mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n, m;
cin >> n >> m;
vector<int> a(n + 1);
for (int i = 1; i <= n; i ++ )
{
cin >> a[i];
a[i] = a[i] % m;
}
if (n > m)
{
cout << "YES\n";
return;
}
vector<vector<bool>> dp(n + 1, vector<bool>(m + 1));
for (int i = 1; i <= n; i ++ ) dp[i][a[i]] = true;
for (int i = 1; i <= n; i ++ )
{
for (int j = 0; j <= m; j ++ )
{
if (dp[i - 1][j])
{
dp[i][(j + a[i]) % m] = true;
dp[i][j] = dp[i - 1][j];
}
}
}
for (int i = 1; i <= n; i ++ )
{
if (dp[i][0])
{
cout << "YES\n";
return;
}
}
cout << "NO\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t -- )
{
solve();
}
}
CF 607B Zuma
一开始想跑n遍马拉车,但是突然发现局部最优并不是全局最优
然后这个数据范围也非常dp,于是想到区间dp
dp[i][j]
表示[i, j]全消掉的最小时间,更新的时候取一个中间点 k ,dp[i][j] = dp[i][k] + dp[k + 1][j]
,同时,如果 a[i] 和 a[j] 相等,还有 dp[i][j] = dp[i + 1][j - 1]
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<PII, int> PIII;
const int N = (1 << 19);
const int mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n;
cin >> n;
vector<int> a(n + 1);
for (int i = 1; i <= n; i ++ ) cin >> a[i];
vector<vector<int>> dp(n + 1, vector<int>(n + 1, INF));
for (int i = 1; i <= n; i ++ )
{
dp[i][i] = 1;
if (i != n) dp[i + 1][i] = 1;
}
for (int len = 2; len <= n; len ++ )
{
for (int i = 1; i + len - 1 <= n; i ++ )
{
int j = i + len - 1;
for (int k = i; k + 1 <= j; k ++ )
{
dp[i][j] = min(dp[i][k] + dp[k + 1][j], dp[i][j]);
}
if (a[i] == a[j]) dp[i][j] = min(dp[i][j], dp[i + 1][j - 1]);
}
}
cout << dp[1][n] << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t -- )
{
solve();
}
}
CF 1401D Maximum Distributed Tree
这道题纯粹考每条边会经过多少次,这次遇到了就要记住了,size[v] * (n - size[v])
,size用dfs预处理一下即可
次数多的赋值大,次数少的赋值小即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<PII, int> PIII;
const int N = (1 << 19);
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n;
cin >> n;
vector<vector<int>> g(n + 1);
vector<int> cnt;
for (int i = 0; i < n - 1; i ++ )
{
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
vector<int> size(n + 1, 1);
function<void(int, int)> dfs = [&](int u, int fa)
{
for (int i = 0; i < g[u].size(); i ++ )
{
int j = g[u][i];
if (j == fa) continue;
dfs(j, u);
size[u] += size[j];
cnt.push_back(size[j] * (n - size[j]));
}
};
dfs(1, -1);
int m;
cin >> m;
vector<int> p(m);
for (int i = 0; i < m; i ++ ) cin >> p[i];
int ans = 0;
if (m < n - 1)
{
sort(p.begin(), p.end(), greater<int>());
sort(cnt.begin(), cnt.end(), greater<int>());
for (int i = 0; i < m; i ++ ) ans = (ans + (p[i] * cnt[i]) % mod) % mod;
for (int i = m; i < n - 1; i ++ ) ans = (ans + cnt[i]) % mod;
}
else
{
sort(p.begin(), p.end());
sort(cnt.begin(), cnt.end());
for (int i = n - 1; i < m; i ++ ) p[n - 2] = (p[n - 2] * p[i]) % mod;
for (int i = 0; i < n - 1; i ++ ) ans = (ans + (p[i] * cnt[i]) % mod) % mod;
}
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t -- )
{
solve();
}
}
CF 1329A Dreamoon Likes Coloring
被dp伤透之后还是贪心大法好啊,,
首先发现如果所有 l 加在一起都不能到 n 的时候是一定不会实现的,然后尽可能让所有 p 小,也就是每次p只往右挪一个,如果有哪一次会超出 n 的话也是不能实现的
然后贪心去想,从后往前填数,每次都尽可能让p更小,直到剩下的p只能一个挨着一个为止(好像有点抽象,不如看代码好了)
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<PII, int> PIII;
const int N = (1 << 19);
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n, m;
cin >> n >> m;
int sum = 0, pos = 1;
vector<int> a(m);
for (int i = 0; i < m; i ++ ) cin >> a[i], sum += a[i];
if (sum < n)
{
cout << -1 << '\n';
return;
}
for (int i = 0; i < m; i ++ )
{
if (pos + a[i] - 1 > n)
{
cout << "-1\n";
return;
}
pos ++ ;
}
pos = n - a[m - 1] + 1;
bool flag = false;
vector<int> ans(m);
ans[m - 1] = pos;
for (int i = m - 2; i >= 0; i -- )
{
if (flag)
{
pos -- ;
ans[i] = pos;
if (pos + a[i] - 1 > n)
{
cout << -1 << '\n';
return;
}
continue;
}
if ((pos - a[i] - 1) < i)
{
pos = i + 1;
ans[i] = pos;
flag = true;
}
else pos -= a[i], ans[i] = pos;
if (pos + a[i] - 1 > n)
{
cout << -1 << '\n';
return;
}
}
for (auto t : ans) cout << t << ' ';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t -- )
{
solve();
}
}
CF 584D Dima and Lisa
看了下题解说是啥哥德巴赫猜想,头大了
总的来说就是,如果 n 是质数就直接输出一个 n ,如果不是就先把n减去3,变成合数,哥德巴赫猜想说>=4的合数可以拆成两个质数相加,枚举一下就可以
这一题的收获是:质数是密集的,每300个数就一定会出现质数
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<PII, int> PIII;
const int N = 1e8 + 3;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
bool check_prime(int x)
{
for (int i = 2; i <= sqrt(x); i ++ )
{
if (x % i == 0) return false;
}
return true;
}
void solve()
{
int n;
cin >> n;
if (check_prime(n)) cout << 1 << '\n' << n << '\n';
else if (n == 4) cout << 2 << '\n' << 2 << ' ' << 2 << '\n';
else if (n == 6) cout << 2 << '\n' << 3 << ' ' << 3 << '\n';
else
{
cout << 3 << '\n' << 3 << ' ';
n -= 3;
for (int i = 2; i < n; i ++ )
{
if (check_prime(i) && check_prime(n - i))
{
cout << i << ' ' << n - i;
return ;
}
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t -- )
{
solve();
}
}