下午训练赛的榜歪得吓人,来补一下题。
题目链接
双指针两端遍历即可
#include
using namespace std;
#define int long long
#define INF 0x3f3f3f3f
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
const int N = 11;
void solve()
{
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i ++ ) cin >> a[i];
sort(a.begin(), a.end());
int i = 2, j = n - 2;
int sum1 = a[0] + a[1], sum2 = a[n - 1];
int cnt1 = 2, cnt2 = 1;
while (i <= j)
{
if (sum1 < sum2 && cnt1 > cnt2)
{
cout << "YES\n";
return;
}
else if (sum1 >= sum2)
{
sum2 += a[j];
cnt2 ++ ;
j -- ;
}
else if (cnt1 <= cnt2)
{
sum1 += a[i];
cnt1 ++ ;
i ++ ;
}
}
if (sum1 < sum2 && cnt1 > cnt2)
{
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();
}
}
题目链接
每个区间分一个前k大的数就行了,剩下就是简单组合数学
#include
using namespace std;
#define int long long
#define INF 0x3f3f3f3f
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
const int N = 11;
const int mod = 998244353;
void solve()
{
int n, k;
cin >> n >> k;
vector<PII> a(n);
for (int i = 0; i < n; i ++ )
{
a[i].second = i;
cin >> a[i].first;
}
sort(a.begin(), a.end());
int ans = 0;
for (int i = n - 1; i >= n - k; i -- ) ans += a[i].first;
int cnt = 1;
vector<int> tmp;
for (int i = n - 1; i >= n - k; i -- ) tmp.push_back(a[i].second);
sort(tmp.begin(), tmp.end());
for (int i = 1; i < tmp.size(); i ++ ) cnt = cnt * (tmp[i] - tmp[i - 1]) % mod;
cout << ans << ' ' << cnt << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t -- )
{
solve();
}
}
题目链接
前面全取1,后面取S-(n-1)即可
主要思路是让能被替代的数尽可能多,如果是1 2 4 8这种取法,互相之间不能被替代,所以能够组成的数就多了
#include
using namespace std;
#define int long long
#define INF 0x3f3f3f3f
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
const int N = 11;
const int mod = 998244353;
void solve()
{
int n,s;
cin >> n >> s;
if (2 * n > s)
{
cout << "NO\n";
return;
}
cout << "YES\n";
for (int i = 0; i < n - 1; i ++ ) cout << 1 << ' ';
cout << s - (n - 1) << '\n';
cout << s - n << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t -- )
{
solve();
}
}
题目链接
打表找规律(这么有意思的题到底哪里毒瘤了 ^ _ ^
#include
using namespace std;
#define int long long
#define INF 0x3f3f3f3f
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
const int N = 11;
const int mod = 998244353;
void solve()
{
int k;
cin >> k;
int d = 1;
int ans = 0;
auto sum = [&](int x)
{
string s = to_string(x);
int res = 0;
for (int i = 0; i < s.size(); i ++ )
{
res += s[i] - '0';
}
return res;
};
for (int i = 0; i < k; i ++ )
{
if ((ans + d * 10) * sum(ans + d) < (ans + d) * sum(ans + d * 10)) d *= 10;
ans += d;
cout << ans << '\n';
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t -- )
{
solve();
}
}
题目链接
二分左右边界即可
二分的时候可以修改条件来保证一定能找到你想找到的值,否则可能会出现没有符合条件的点的情况
#include
using namespace std;
#define int long long
#define INF 0x3f3f3f3f
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
const int N = 11;
const int mod = 998244353;
void solve()
{
int n, q;
cin >> n >> q;
string s;
cin >> s;
s = " " + s;
vector<char> t(q), d(q);
for (int i = 0; i < q; i ++ ) cin >> t[i] >> d[i];
auto check = [&](int x)
{
for (int i = 0; i < q; i ++ )
{
if (t[i] == s[x])
{
if (d[i] == 'L') x -- ;
else x ++ ;
if (x <= 0) return 0;
else if (x > n) return 1;
}
}
return 2;
};
int l = 0, r = n + 1;
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid) == 0) l = mid;
else r = mid - 1;
}
int ansl = r;
l = 0, r = n + 1;
while (l < r)
{
int mid = l + r >> 1;
if (check(mid) == 1) r = mid;
else l = mid + 1;
}
int ansr = r;
cout << ansr - ansl - 1 << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t -- )
{
solve();
}
}
题目链接
设p[i]
是i
到根结点的边权值异或和,根据异或的性质可以得到点u
和v
的边权异或和就是p[u] ^ p[v]
输入边的时候记录点的度数,度数为偶数的可以不用管,因为会相抵消
根据已给的边权信息,可以利用dfs得到一组可行解(设每个连通块遍历的第一个点w
的p[w] = 0
),同时在遍历的时候发现矛盾直接返回NO
之后就是让所有边权异或和最小了,先记录所有度为奇数的点的异或和为ans
,连通块点数为偶数的,异或值会相抵消不用管,只要遇见奇数,只需要让连通块中的点与当前ans
取异或就行
#include
using namespace std;
#define int long long
#define INF 0x3f3f3f3f
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
const int N = 11;
const int mod = 998244353;
void solve()
{
int n, m;
cin >> n >> m;
vector<PII> edge(n - 1);
vector<int> du(n + 1), p(n + 1), size(n + 1), root(n + 1);
for (int i = 0; i < n - 1; i ++ )
{
cin >> edge[i].first >> edge[i].second;
du[edge[i].first] ++ , du[edge[i].second] ++ ;
}
vector<vector<PII>> g(n + 1);
for (int i = 0; i < m; i ++ )
{
int a, b, c;
cin >> a >> b >> c;
g[a].push_back(make_pair(b, c));
g[b].push_back(make_pair(a, c));
}
function<void(int, int)> dfs = [&](int u, int rt)
{
root[u] = rt;
for (int i = 0; i < g[u].size(); i ++ )
{
int j = g[u][i].first;
if (!root[j])
{
p[j] = (p[u] ^ g[u][i].second);
dfs(j, rt);
}
else if (p[j] != (p[u] ^ g[u][i].second))
{
cout << "NO\n";
exit(0);
}
}
};
for (int i = 1; i <= n; i ++ )
{
if (root[i]) continue;
dfs(i, i);
}
int ans = 0;
for (int i= 1; i <= n; i ++ )
{
if (du[i] % 2 != 0)
{
ans ^= p[i];
size[root[i]] ++ ;
}
}
for (int i = 1; i <= n; i ++ )
{
if (size[i] % 2 == 0) continue;
for (int j = 1; j <= n; j ++ )
{
if (root[j] == i) p[j] ^= ans;
}
break;
}
cout << "YES\n";
for (int i = 0; i < n - 1; i ++ )
{
cout << (p[edge[i].first] ^ p[edge[i].second]) << ' ';
}
cout << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t -- )
{
solve();
}
}