B.Cake 2
题意:
给定一个正n边形,每个顶点与距离k的顶点相连
问最后一共被切成多少个图形
题解:
手动画图,找规律,k*2=n时,答案就是n,被切成n份
其他情况答案是
n
∗
m
i
n
(
n
,
n
−
k
)
+
1
n*min(n,n-k)+1
n∗min(n,n−k)+1
代码:
#include<bits/stdc++.h>
using namespace std;
typedef __int128 i128;
typedef long long ll;
typedef double db;
const db PI = acos(-1);
typedef array<ll, 2> PII; // vector<PII> a(n + 1);
const ll inf = 2e18 + 10;
const int mod = 998244353;
const int maxn = 2e5 + 10;
bool multi = 0;
void Solve() {
ll n, k; cin >> n >> k;
if(n % 2 == 0 && k == n / 2) cout << n << "\n";
else {
if(k >= (n + 1) / 2) k = n - k;
cout << n * k + 1 << "\n";
}
}
signed main() {
// freopen("test.in","r",stdin);
// freopen("code.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
ll T = 1;
if(multi) cin >> T;
while(T -- ) {
Solve();
}
return 0;
}
A.Cake
题意:
给定一棵树,每条边有值0或1,Grammy 和Oscar轮流从根节点选一条边走,直到根节点,记录走过的01串。
然后Oscar把蛋糕分为m份(01串的长度)。1代表Grammy选一份,0代表Oscar选一份。
问两人都想拿最大比例的蛋糕,问最后Grammy能拿的比例。
题解:
由于是由Oscar分配,他会尽量让自己多拿,例如011就可以把蛋糕全分在第一份,就可以全部拿走了。
1100,可以把蛋糕分为4份,可以拿一半,发现我们需要找的是01串的0的前缀比例最大的时候。
现在考虑两人在树上得到的01串。
轮到奇数次选的时候Grammy想要让0的前缀比例最小。
轮到偶数次选的时候Oscar想要让0的前缀比例最小大。
就先dfs每个节点0的前缀最大和最小的的节点,两人轮流选择。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef __int128 i128;
typedef long long ll;
typedef double db;
const db PI = acos(-1);
typedef array<ll, 2> PII; // vector<PII> a(n + 1);
const ll inf = 2e18 + 10;
const int mod = 998244353;
const int maxn = 2e5 + 10;
bool multi = 1;
struct node {
ll u, ze, on;
};
void dfs(ll x, ll fa, vector<vector<PII>> &e, ll ff, vector<db> &ans, ll las) {
db anss = 0;
for(auto p : e[x]) {
ll y = p[0], k = p[1];
if(y == fa) continue;
ll f = ff ^ 1;
dfs(y, x, e, f, ans, k);
if(ff) {
if(anss == 0) anss = ans[y];
else anss = max(anss, ans[y]);
} else {
if(anss == 0) anss = ans[y];
anss = min(anss, ans[y]);
}
}
if(anss == 0) return ;
if(!las) {
if(anss < ans[x]) ans[x] = anss;
} else {
ans[x] = anss;
}
}
void Solve() {
ll n; cin >> n;
vector<vector<PII>> e(n + 1);
vector<db> ans(n + 1);
vector<bool> vis(n + 1);
for(ll i = 1; i < n; i ++ ) {
ll x, y, k; cin >> x >> y >> k;
e[x].push_back({y, k});
e[y].push_back({x, k});
}
queue<node> q;
q.push((node){1, 0, 0});
while(!q.empty()) {
node d = q.front(); q.pop();
ll u = d.u, ze = d.ze, on = d.on;
for(auto p : e[u]) {
ll v = p[0], k = p[1];
if(vis[v] == true) continue;
else vis[v] = true;
if(k == 1) {
ans[v] = (db)(on + 1) / (db)(on + ze + 1);
q.push((node){v, ze, on + 1});
}
else {
ans[v] = (db)on / (db)(on + ze + 1);
q.push((node){v, ze + 1, on});
}
}
}
dfs(1, 1, e, 1, ans, 0);
db anss = 0;
for(auto p : e[1]) {
anss = max(ans[p[0]], anss);
}
cout << fixed << setprecision(10);
cout << anss << "\n";
}
signed main() {
// freopen("test.in","r",stdin);
// freopen("code.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
ll T = 1;
if(multi) cin >> T;
while(T -- ) {
Solve();
}
return 0;
}
D.Puzzle: Wagiri
题意:
给你一个无向连通图,每条边有名称Qie和Lun。
现在可以删掉一些边满足以下条件:
·这个图的Qie边不在任何循环上。
·这个图的Lun边一定在循环上。
·图一定是连通的。
问你能不能实现,如果能,保留哪些边。
题解:
把两种边分开存储,在Lun边组成的图中,我们要找环,用tarjan算法,把成环的边加入答案,还有用并查集维护,最后遍历Qie边,把没有连通的节点连在一起,加入最后答案是连通的,则有答案,否则没有
代码:
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=3e5;
int n,m;
pair<int,int>b[N],d[N];
set<pair<int,int>>ans;
vector <int>e[N],st;
int p[N],x,y;
int low[N],dfn[N];
int cnt;
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
void dfs(int now, int pre) {
low[now] = dfn[now] = ++cnt;
st.push_back(now);
for (auto i: e[now]) {
if (i == pre) continue;
if (!dfn[i]) {
dfs(i, now);
low[now] = min(low[now], low[i]);
} else
low[now] = min(low[now], low[i]);
}
if (low[now] == dfn[now]) {
while (st.back() != now) {
x=find(st.back());
y=find(now);
if(x>y)swap(x,y);
p[y]=find(x);
st.pop_back();
}
st.pop_back();
}
}
void solve()
{
cin>>n>>m;
int u,v;
string ss;
int t=0;
for(int i=1;i<=n;i++){
p[i]=i;
}
int t2=0;
for(int i=1;i<=m;i++){
cin>>u>>v;
cin>>ss;
if(ss[0]=='L'){
e[u].push_back(v);
e[v].push_back(u);
d[t2++]={u,v};
}
else {
b[t++]={u,v};
}
}
for(int i=1;i<=n;i++){
if(dfn[i]==0){
dfs(i,0);
}
}
for(int i=0;i<t2;i++){
x=find(d[i].first);
y=find(d[i].second);
if(x>y)swap(x,y);
if(x==y){
ans.insert(d[i]);
}
}
for(int i=0;i<t;i++){
x=find(b[i].first);
y=find(b[i].second);
if(x>y)swap(x,y);
if(x!=y){
ans.insert(b[i]);
p[y]=x;
}
}
for(int i=1;i<=n;i++){
x=find(i);
if(p[x]!=1){
cout<<"NO\n";
return ;
}
}
cout<<"YES\n";
cout<<ans.size()<<'\n';
for(;ans.size()>0;){
auto an=*ans.begin();
cout<<an.first<<' '<<an.second<<'\n';
ans.erase(ans.begin());
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int T=1;
// cin>>T;
while(T--){
solve();
}
return 0;
}