牛客周赛 Round 35
小红的字符串切割
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
typedef double db;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
const ll inf = 1ll << 60;
const int N = 6010;
vector<vector<int>> dp, e, vis;
void solve()
{
string s;
cin >> s;
int n = s.size();
n /= 2;
string a = s.substr(0, n);
string b = s.substr(n);
cout << a << endl;
cout << b << endl;
}
int main()
{
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
return 0;
}
小红的数组分配
解题思路:
计算每个数出现次数,如果都是偶数,平均分配即可。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
typedef double db;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
const ll inf = 1ll << 60;
const int N = 6010;
vector<vector<int>> dp, e, vis;
void solve()
{
int n;
cin >> n;
vector<int> a(2 * n + 1);
map<int, int> cnt;
for (int i = 1; i <= 2 * n; i++)
{
cin >> a[i];
cnt[a[i]]++;
}
for (auto t : cnt)
{
if (t.se & 1)
{
puts("-1");
return;
}
}
vector<int> sa, sb;
for (auto t : cnt)
{
int m = t.se / 2;
for (int i = 1; i <= m; i++)
{
sa.push_back(t.fi);
sb.push_back(t.fi);
}
}
for (auto x : sa)
{
cout << x << ' ';
}
cout << endl;
for (auto x : sb)
{
cout << x << ' ';
}
cout << endl;
}
int main()
{
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
return 0;
}
小红关鸡
解题思路:
排序,双指针维护长度小于等于\(k\)的区间,不断更新概率最大值即可。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
typedef double db;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
const ll inf = 1ll << 60;
const int N = 6010;
vector<vector<int>> dp, e, vis;
void solve()
{
ll n, k;
cin >> n >> k;
vector<ll> a(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
sort(a.begin() + 1, a.end());
int l = 1;
int r = 1;
double ans = 0;
while (l <= r && r <= n)
{
while (r + 1 <= n && a[r + 1] - a[l] <= k)
{
r++;
}
ans = max(ans, (r - l + 1.0) / (1.0 * n));
l++;
if (l > r && r + 1 <= n)
{
r++;
}
}
printf("%.10lf", ans);
}
int main()
{
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
return 0;
}
小红的排列构造
解题思路:
大于\(n\)的数要改,小于等于\(n\)且出现次数大于\(1\)的要改。
改成合法范围内,没出现过的数即可。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
typedef double db;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
const ll inf = 1ll << 60;
const int N = 6010;
vector<vector<int>> dp, e, vis;
void solve()
{
int n;
cin >> n;
vector<int> a(n + 1);
int ans = 0;
map<int, int> cnt;
int cur = 1;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
if (a[i] > n)
{
ans++;
}
else if (cnt[a[i]] > 0)
{
ans++;
}
cnt[a[i]]++;
}
cout << ans << endl;
for (int i = 1; i <= n; i++)
{
if ((a[i] <= n && cnt[a[i]] > 1) || (a[i] > n))
{
while (cnt[cur] > 0)
{
cur++;
}
cnt[a[i]]--;
cout << i << ' ' << cur << endl;
cnt[cur]++;
}
}
}
int main()
{
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
return 0;
}
小红的无向图构造
解题思路:
点\(1\)为根,先构造有根树。最短路距离就是深度。
若最短路距离之间出现断层,即有深度\(1,3\)但无深度\(2\),无解。按深度构造有根树,消耗边\(n - 1\)条。
对于剩余的边,我们有两种处理方法:
- 同深度结点相连。
- 深度相差为\(1\)的两节点相连。
若如此连接完边还有剩余,那么无解。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
typedef double db;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
const ll inf = 1ll << 60;
const int N = 6010;
void solve()
{
int n, m;
cin >> n >> m;
vector<pii> a(n + 1);
vector<vector<int>> d(n + 10, vector<int>());
map<pii, bool> vis;
for (int i = 1; i <= n; i++)
{
cin >> a[i].fi;
a[i].se = i;
d[a[i].fi].push_back(i);
}
if (m < n - 1)
{
puts("-1");
return;
}
sort(a.begin() + 1, a.end());
for (int i = 2; i <= n; i++)
{
if (a[i].fi - a[i - 1].fi > 1)
{
puts("-1");
return;
}
}
m -= n - 1;
ll res = 0;
for (int i = 1; i <= n; i++)
{
ll x = d[i].size();
if (x > 0)
{
res += (x * (x - 1)) / 2;
}
ll y = d[i + 1].size();
if (x > 0 && y > 0)
{
res += (x - 1) * y;
}
}
if (m > res)
{
puts("-1");
return;
}
vector<pii> ans;
for (int i = 1; i <= n; i++)
{
for (int j = 0; j < (int)d[i].size(); j++)
{
ans.emplace_back((pii){d[i - 1][0], d[i][j]});
vis[{d[i - 1][0], d[i][j]}] = true;
}
}
// for (int i = 2; i <= n; i++)
// {
// ans.emplace_back((pii){a[i].se, d[a[i].fi - 1][0]});
// vis[{a[i].se, d[a[i].fi - 1][0]}] = true;
// }
for (int i = 0; i <= n; i++)
{
if (m == 0)
{
break;
}
for (int j = 0; j <= (int)d[i].size() - 1; j++)
{
for (int k = j + 1; k <= (int)d[i].size() - 1; k++)
{
if (vis[{d[i][j], d[i][k]}] == false)
{
vis[{d[i][j], d[i][k]}] = true;
ans.push_back({d[i][j], d[i][k]});
m--;
if (m == 0)
{
break;
}
}
}
if (m == 0)
{
break;
}
}
if (m == 0)
{
break;
}
}
for (int i = 0; i <= n; i++)
{
if (m == 0)
{
break;
}
for (int j = 0; j <= (int)d[i].size() - 1; j++)
{
for (int k = 0; k <= (int)d[i + 1].size() - 1; k++)
{
if (vis[{d[i][j], d[i + 1][k]}] == false)
{
vis[{d[i][j], d[i + 1][k]}] = true;
ans.push_back({d[i][j], d[i + 1][k]});
m--;
if (m == 0)
{
break;
}
}
}
if (m == 0)
{
break;
}
}
if (m == 0)
{
break;
}
}
if (m > 0)
{
puts("-1");
return;
}
for (auto t : ans)
{
cout << t.fi << ' ' << t.se << endl;
}
cout << endl;
}
int main()
{
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
return 0;
}
小红的子序列权值和(easy)
小红的子序列权值和(hard)
解题思路:
一个数的因子个数取决于他质因数分解后,质因子的次数。\(x = p_1^{\alpha_1}p_2^{\alpha_2}\)。那么\(x\)的因子个数为\((\alpha_1 + 1)\times (\alpha_2 + 1)。\)
本题中只有两个质因子\((2,3)\),所以关键就是维护他们次数之和。
\(dp[i]:考虑前i个数字,他们的序列权值和为dp[i]\)。
$s[2]:考虑前i个数字,他们序列构成的每个子序列,设子序列中元素乘积为x_i,x_i = 2{\alpha_i}3 .s[2] = \sum(\alpha_i + 1) $。
\(s[3] = \sum(\beta_i + 1)\)。
考虑\(dp[i]\)时,首先,相比\(dp[i -1]\),会多出\(2^{i -1}\)个子序列。这些子序列中有一个是\(a[i]\),其余\(2^{i-1} - 1\)个子序列为\(dp[i-1]\)中的所有子序列分别乘以\(a[i]\)。
-
\(a[i] = 1\):那么前面所有的\(\alpha_i 和\beta_i\)都不会发生变化,只是单纯子序列的增加。
- \(dp[i] = 2 * dp[i-1] + 1\),其中\(+1\)是因为\(a[i] =1,a[i] 的因子只有一个\)。
- \(s[2] = 2 * s[2] + 1\),对应上面解释。\(s[3]\)同理。
-
\(a[1] = 2\):前面\(2^{i -1}\)个子序列要乘以\(a[i]\),\(\alpha_i + 1\)。
-
\(dp[i] = 2 * dp[i - 1] + s[3] + 2\)。其中,\(+s[3]\)是因为质因子\(2\)的次数\(+1\),参照最初给的根据质因子次数求因子个数的公式。\(+1\)是因为\(a[i] = 2, a[i]的因子有2个\)。
-
\(s[2] = 2 *s[2] + 2^{i -1}\),\(s[3] = 2 * s[3] + 1\)。
-
-
\(a[1] = 3\):前面\(2^{i -1}\)个子序列要乘以\(a[i]\),\(\beta_i + 1\)。
-
\(dp[i] = 2 * dp[i - 1] + s[2] + 2\)。其中,\(+s[2]\)是因为质因子\(3\)的次数\(+1\),参照最初给的根据质因子次数求因子个数的公式。\(+1\)是因为\(a[i] = 3, a[i]的因子有2个\)。
-
\(s[3] = 2 *s[3] + 2^{i -1}\),\(s[2] = 2 * s[2] + 1\)。
-
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
typedef double db;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
const int mod = 1e9 + 7;
ll qmi(ll a, ll b)
{
ll res = 1;
while (b)
{
if (b & 1)
{
res = res * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return res;
}
void solve()
{
int n;
cin >> n;
vector<ll> a(n + 1);
vector<ll> cnt(4, 0), s(4, 0);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
vector<ll> dp(n + 1);
ll ans = 0;
for (int i = 1; i <= n; i++)
{
if (a[i] == 1)
{
dp[i] = ((dp[i - 1] * 2) + 1) % mod;
s[3] = (2 * s[3] + 1) % mod;
s[2] = (2 * s[2] + 1) % mod;
}
else if (a[i] == 2)
{
dp[i] = (2 * dp[i - 1] + s[3] + 2) % mod;
dp[i] %= mod;
s[3] = (2 * s[3] + 1) % mod;
s[2] = ((2 * s[2] + 1) + (qmi(2, i - 1))) % mod;
// cnt[2]++;
// s[2] = s[2] + (qmi(2, i - 1) * s[3]) + 2;
// s[2] %= mod;
}
else
{
dp[i] = (2 * dp[i - 1] + s[2] + 2) % mod;
dp[i] %= mod;
s[2] = (2 * s[2] + 1) % mod;
s[3] = ((2 * s[3] + 1) + (qmi(2, i - 1))) % mod;
// cnt[3]++;
// s[3] = s[3] + (qmi(2, i - 1) - 1) + 3;
// s[3] %= mod;
}
// cout << i << ' ' << s[2] << ' ' << s[3] << ' ' << dp[i] << endl;
}
cout << dp[n] << endl;
}
int main()
{
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
return 0;
}
标签:return,int,ll,35,牛客,long,using,Round,dp
From: https://www.cnblogs.com/value0/p/18050841