A 小紫的均势博弈
int n;
void solve()
{
cin >> n;
if (n & 1) cout << "kou" << endl;
else cout << "yukari" << endl;
}
B 小紫的劣势博弈
贪心题目
const int N = 1e5 + 10;
int n;
LL a[N];
void solve()
{
cin >> n;
for (int i = 1;i <= n;i ++) cin >> a[i];
sort(a + 1,a + 1 + n);
LL ans = 0;
for (int i = 1;i <= n;i ++)
{
if (i & 1) ans += a[i];
else ans -= a[i];
}
cout << ans << endl;
}
C 小紫的01串操作
计数是否连续的1或0的段的数量,是否小于2
const int N = 1e5 + 10;
string s;
void solve()
{
cin >> s;
int c0 = 0,c1 = 0;
char pre = s[0];
if (s[0] == '0') c0 ++;
else c1 ++;
for (int i = 1;i < s.size();i ++)
{
if (s[i] != pre)
{
if (s[i] == '1') c1 ++;
else c0++;
pre = s[i];
}
}
// cout << c0 << " " << c1 << endl;
if (c1 <= 2 || c0 <= 2) cout << "Yes" << endl;
else cout << "No" << endl;
}
D 小紫的优势博弈
这个题看看牛客官方的视频讲解,这个题写的很优雅,思路巧妙且代码优雅
const int N = 2e5 + 10;
int n;
string s;
void solve()
{
cin >> n >> s;
s = " " + s;
LL c0 = 0,c1 = 0;
LL ans = 0;
map<LL,LL> mp;
mp[0] = 1;
//01]01011
for (int i = n;i > 1;i --)
{
c0 ^= (s[i] == '0');
c1 ^= (s[i] == '1');
LL t = (c0 << 1) | c1;
ans += mp[t];
mp[t] = 1;
}
cout << fixed << setprecision(10) << 1.0 * ans / n << endl;
}
E 小紫的线段染色
如果有线段重叠次数>=3(巧妙利用离散化+差分求重叠次数),无论怎么染色都不会满足要求
剩下的求染色的线段的编号就是贪心
typedef pair<LL,LL> PLL;
const int N = 1e5 + 10;
int n;
struct Node
{
int l,r,id;
bool operator< (const Node& t) const
{
if (l == t.l) return r < t.r;
return l < t.l;
}
}a[N];
int ans[N];
void solve()
{
cin >> n;
vector<PLL> v;
for (int i = 1;i <= n;i ++)
{
cin >> a[i].l >> a[i].r;
a[i].id = i;
v.push_back({a[i].l,1});//差分
v.push_back({a[i].r + 1,-1});//差分
}
sort(v.begin(),v.end());
LL sum = 0;//利用前缀和思想,判断是否有重叠>=3次
for (auto &[x,y] : v)
{
sum += y;
if (sum >= 3)
{
cout << -1 << endl;
return;
}
}
sort(a + 1,a + 1 + n);
int r = -1,id = 0;
for (int i = 1;i <= n;i ++)
{
if (a[i].l <= r) ans[a[i].id] = (ans[id] ^ 1);
if (a[i].r > r) r = a[i].r,id = a[i].id;
}
vector<int> ans1;
for (int i = 1;i <= n;i ++)
if (ans[i])
ans1.push_back(i);
if (!ans1.size()) ans1.push_back(1);//全是分开的,都没有交集。类似[] [] []
cout << ans1.size() << endl;
for (auto &t : ans1) cout << t << " ";
}
F 小紫的树上染色 最大值最小
贪心的想法:从叶节点开始自底往上贪心,记录i节点及其子树的数量sz,如果>二分的联通块的大小,就cnt++(表示染了一个紫色块,将这些红色块分割开,sz置为0),如果最后的sz<=k,说明二分的这个连通块偏大,需要缩小,反之就扩大
自底往上的树形dfs
可以参考一下画的(丑)图
const int N = 1e5 + 10;
int n,k;
vector<int> g[N];
int cnt;
int dfs(int x,int pre,int size)
{
int sz = 1;//加上当前的大小:1
for (auto &y : g[x])
{
if (y == pre) continue;
sz += dfs(y,x,size);
}
if (sz > size) //超过了红色连通块大小限制,染色成紫色
{
cnt++;
return 0;
}
else return sz;//没超过就继续累加
}
bool check(int x)
{
cnt = 0;
dfs(1,-1,x);
return cnt <= k;
}
void solve()
{
cin >> n >> k;
for (int i = 1;i < n;i ++)
{
int x,y;cin >> x >> y;
g[x].push_back(y);
g[y].push_back(x);
}
//二分红色联通块的最大值
int l = 0,r = n + 1;
while(l + 1 != r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid;//最大值最小
else l = mid;
}
if (check(l)) cout << l << endl;//如果满足就 取小
else cout << r << endl;//不满足再取大
}