2023年8月初补题

看这个人的专栏

https://blog.csdn.net/qq_42555009/category_8770183.html

有一定思维难度,贪心,用multiset实现

翻译:

链接:https://ac.nowcoder.com/acm/contest/33187/H
来源:牛客网

在夜之城的中心有一座高大的建筑,叫做Arasaka塔。每天都有人在Arasaka塔里上上下下。

Arasaka塔有k层。今天,有n个人要乘电梯,第i个人想从ai楼层去到bi楼层。电梯一次最多可以搭载m个人,并且它从一楼开始。电梯上升或下降一层需要1单位时间。人们进出电梯的时间可以忽略不计。

然而,今天电梯有些问题。电梯的运行方向不能再任意改变。当电梯正在下行时,只有当它到达一楼时才能改变其运行方向。

将所有人送到他们的目的地并让电梯回到一楼需要的最少时间是多少?

拓展,如果是某个批次,人数,都不一样怎么办。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+10;
struct node{int l,r,op;bool operator<(const node&b)const{return r<b.r;}
}a[N];
int n,m,k;
typedef pair<int,int>PII;
multiset<PII>S[2];
signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n>>m>>k;for(int i=1;i<=n;i++){int l,r;cin>>l>>r;if(l<r)a[i]={l,r,0};else a[i]={r,l,1};}sort(a+1,a+1+n);int ans=0;for(int i=n;i>=1;i--){int l=a[i].l,r=a[i].r,op=a[i].op;auto it=S[op].lower_bound({r,1});if(it==S[op].end()){ans+=2*(r-1);S[0].insert({r,m});S[1].insert({r,m});}it=S[op].lower_bound({r,1});
//         int room=it->second;int room=(*it).second;S[op].erase(it);if(--room)S[op].insert({r,room});S[op].insert({l,1});}cout<<ans;
}

矩阵技巧

链接:https://ac.nowcoder.com/acm/contest/33187/I
来源:牛客网

在一个名为江湖的虚拟世界里,有 n 名拥有独特技能的武术大师。然而,由于缺乏锻炼,他们不再是熟练的大师,甚至开始发胖!为了解决这个问题,他们决定举办一个名为 “让脂肪紧张” (LFT, IF: 0.053) 的武术大会,他们可以在其中深入学习,以提升他们的技能。

第 i 名武术大师有两个属性,即能力属性和技能属性。第 i 名大师的能力属性可以用长度为 k 的向量 Xi 表示,他的技能属性可以用长度为 d 的向量 Yi 表示。

在武术大会上,一个大师会深入学习其他每一个武术大师以提升他们的技能。

定义第 i 名大师和第 j 名大师之间的学习效率为 le(i,j),即他们的能力属性 Xi 和 Xj 之间的余弦相似度。正式地,我们有:

le(i,j) = Xi * Xj / (||Xi|| * ||Xj||)

其中 “*” 表示两个向量之间的点积,“|| ||” 表示向量的大小。注意,le(i,i) = 1 总是成立。

在深入学习其他人后,第 i 名大师的技能属性将变为:

Yi_new = Σ(j=1 to n) le(i,j) * Yj

n 名武术大师的学习过程是同时发生的。

请计算所有武术大师的新技能属性。在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
vector<vector<double>> operator*(vector<vector<double>> a, vector<vector<double>> b)
{int n = a.size(), m = a[0].size(), k = b[0].size();vector<vector<double>> ans(n, vector<double>(k, 0));for (int i = 0; i < n;i++)for (int j = 0; j < k;j++)for (int l = 0; l < m;l++)ans[i][j] += a[i][l] * b[l][j];return ans;
}
int main()
{int n, k, d;scanf("%d%d%d", &n, &k, &d);vector<vector<double>> a(n, vector<double>(k)), b(k, vector<double>(n)), c(n, vector<double>(d));for (int i = 0; i < n;i++){double all = 0;for (int j = 0; j < k;j++){scanf("%lf", &a[i][j]);all += a[i][j] * a[i][j];}all = sqrt(all);for (int j = 0; j < k; j++){a[i][j] /= all;b[j][i] = a[i][j];}}for (int i = 0; i < n;i++)for (int j = 0; j < d;j++)scanf("%lf", &c[i][j]);auto ans = a * (b * c);for(auto i:ans){for (auto j : i)printf("%.10lf ", j);printf("\n");}return 0;
}

二分+spfa,但是会爆炸爆出double 需要用到log取对数运算

链接:https://ac.nowcoder.com/acm/contest/33187/D
来源:牛客网

Link正在开发一款游戏。在这款游戏中,玩家可以使用各种类型的资源来制作物品,而制作出的物品也可以用来制作其他物品。

正式地说,游戏中有 n 种物品,编号从 1 到 n,并有 m 个配方。在第 i 个配方中,玩家可以使用 k * ai 个第 bi 类物品来制作 k * ci 个第 di 类物品,其中 k 可以是任何正实数。

有一天,他发现一名玩家拥有超过 18,446,744,073,709,551,615 个相同的物品,这导致了服务器崩溃。显然,不使用漏洞这是不可能的。

Link很快发现制作配方中有问题。通过反复制作一些特殊物品,玩家可能会获得无限的资源!

Link不想逐个调整配方,所以他简单地添加了一个参数 w。现在,玩家可以使用 k * ai 个第 bi 类物品来制作 w * k * ci 个第 di 类物品。

Link想知道:他可以设置的最大的 w 是多少,以便没有玩家可以通过反复制作物品获得无限的物品?

#include<bits/stdc++.h>
using namespace std;
const int N=1010,M=2020;
// #define double long double
const double eps=1e-10;
int h[N],e[M],ne[M],n,m,idx;
double w[M];
void add(int a,int b,double c){e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int st[N];
double d[N];
int vis[N],cnt[N];
int spfa(int uu,double x){queue<int>q;q.push(uu);d[uu]=1;vis[uu]=1;while(q.size()){int u=q.front();q.pop();vis[u]=0;st[u]=1;for(int i=h[u];~i;i=ne[i]){int j=e[i];if(d[j]<d[u]+w[i]+x){d[j]=d[u]+w[i]+x;if(!vis[j]){vis[j]=1,q.push(j);if(++cnt[j]>=n)return 1;}}}
//         if(d[uu]>1)return 1;}return 0;
}
int check(double mid){for(int i=1;i<=n;i++)st[i]=0,d[i]=0,vis[i]=0,cnt[i]=0;for(int i=1;i<=n;i++){if(!st[i]){st[i]=1;if(spfa(i,mid))return 1;}}return 0;
}signed main(){ios::sync_with_stdio(0);cin.tie(0);cin>>n>>m;memset(h,-1,sizeof h);for(int i=1;i<=m;i++){int a,b,c,d;cin>>a>>b>>c>>d;add(b,d,log((double)c/a));}double l=0.0,r=1.0;while(r-l>eps){double mid=(l+r)/2;if(check(log(mid)))r=mid;else l=mid;}cout<<fixed<<setprecision(12)<<r;
}

随机化思想+状压dp

在这里插入图片描述

#include<bits/stdc++.h>
#define LL long longusing namespace std;const int MXN=5005;
struct Egde{int v,val,nxt;
}e[MXN*2];int n,k,cnt;
int head[MXN],a[MXN],col[MXN];
LL ans,dp[MXN][(1<<6)];void add(int v,int u,int w){e[++cnt].v=v;e[cnt].val=w;e[cnt].nxt=head[u];head[u]=cnt;
}void dfs(int u,int fa){int v,w;for(int S=0;S<(1<<k);S++) dp[u][S]=-1e17;dp[u][0]=0;dp[u][(1<<col[a[u]])]=0;for(int i=head[u];i;i=e[i].nxt){v=e[i].v; w=e[i].val;if(v==fa) continue;dfs(v,u);for(int S=1;S<(1<<k);S++) dp[v][S]+=w;for(int S=(1<<k)-1;S>=0;S--){for(int T=S;T;T=(T-1)&S){dp[u][S]=max(dp[u][S],dp[u][S-T]+dp[v][T]);if(S-T) ans=max(ans,dp[u][S-T]+dp[v][T]);}}}
}int main(){srand((int)time(0));int T,u,v,w;scanf("%d%d",&n,&k);for(int i=1;i<=n;i++){scanf("%d",&a[i]);}for(int i=1;i<n;i++){scanf("%d%d%d",&u,&v,&w);add(u,v,w); add(v,u,w);}T=200;while(T--){for(int i=1;i<=n;i++) {col[i]=rand()%k;}dfs(1,0); }printf("%lld\n",ans);
}

鸽巢原理??

在这里插入图片描述

#include <bits/stdc++.h>
#define fp(i, a, b) for (int i = a, i##_ = (b) + 1; i < i##_; ++i)
#define fd(i, a, b) for (int i = a, i##_ = (b) - 1; i > i##_; --i)using namespace std;
const int N = 2e7 + 5;
using pii = pair<int, int>;
int n, m;
pii w[N];
unordered_map<int, vector<int>> A, B;
void Solve() {   scanf("%d%d", &n, &m);for (int x, i = 1; i <= n; ++i) scanf("%d", &x), A[x].push_back(i);for (int x, i = 1; i <= m; ++i) scanf("%d", &x), B[x].push_back(i);vector<pii> a, b;pii ma, mb;for (auto &[i, v] : A) {a.push_back({i, v[0]});if (v.size() > 1) ma = {v[0], v[1]};}for (auto &[i, v] : B) {b.push_back({i, v[0]});if (v.size() > 1) mb = {v[0], v[1]};}if (ma.first && mb.first)return printf("%d %d %d %d\n", ma.first, ma.second, mb.first, mb.second), void();b.resi***(b.size(), size_t(2e7 / a.size())));for (auto &[x, i] : a)for (auto &[y, k] : b) {auto [j, l] = w[x + y];if (j && i != j && k != l) {printf("%d %d %d %d\n", i, j, k, l);return;} else w[x + y] = {i, k};}puts("-1");
}
int main() {int t = 1;while (t--) Solve();return 0;
}

bfs

在这里插入图片描述
终点是一个必胜态,从终点出发去bfs,把必胜态丢尽队列去更新
如果有两条边连接着必胜态,必胜,如果这个点有两个以上被必胜态访问过,也必胜

#include <bits/stdc++.h>
using namespace std;
int main()
{int caset, n, m, s, t;scanf("%d", &caset);while (caset--){scanf("%d%d%d%d", &n, &m, &s, &t);vector<vector<int>> deg(n + 1, vector<int>(n + 1, 0));vector<vector<int>> g(n + 1);for (int i = 1, u, v; i <= m; i++){scanf("%d%d", &u, &v);deg[u][v]++;deg[v][u]++;g[u].push_back(v);g[v].push_back(u);}vector<int> vis(n + 1), in(n + 1, 0);queue<int> q;vis[t] = 1;q.push(t);while (!q.empty()){int tp = q.front();q.pop();for (auto i : g[tp]){if (deg[tp][i] > 1){if (!vis[i] && vis[tp]){vis[i] = 1;q.push(i);}}else if (deg[tp][i] == 1 && vis[tp])in[i]++;if (in[i] >= 2 && !vis[i]){vis[i] = 1;q.push(i);}}}if (vis[s])printf("Join Player\n");elseprintf("Cut Player\n");}return 0;
}

二分,差分转前缀和,前缀和转差分

链接:https://ac.nowcoder.com/acm/contest/33195/B
来源:牛客网

在著名的游戏"Fall Guys: Ultimate Knockout"中,有一个叫做"Perfect Match"的关卡。我们将游戏的规则简化如下:你站在一个n×n的网格上,有m种水果。而且,每个网格上都标记有某种水果。保证每种水果在至少1个网格上出现,最多在20个网格上出现。你可以选择一开始就站在任何一个网格上,然后游戏中的大屏幕上会出现一种水果,你需要在倒计时结束之前跑到一个标记着和屏幕上相同水果的网格上。在游戏中,你只能横向或纵向移动,即如果你站在(x1,y1)并移动到(x2,y2),你移动的距离是|x1-x2| + |y1-y2|。
你想选择一个格子作为初始站立的位置,以使在最坏情况下(即所有可能的m种水果都出现在大屏幕上时)你需要移动的距离最小,这样即使在最坏情况下你也有希望不被淘汰!计算这个最小化的距离。

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N=2010;
int n,m,a[N][N];
typedef pair<int,int>PII;
vector<PII>p[N*N];
int s[N][N],v[N][N];
int X[N*N],Y[N*N],x,y;
int ok[N][N];
int check(int d){memset(v,0,sizeof v);for(int c=1;c<=m;c++){x=0,y=0;X[x++]=0;Y[y++]=0;for(auto [i,j]:p[c]){int x1=max(1,i-d);X[x++]=x1;int y1=max(1,j-d);Y[y++]=y1;int x2=min(2*n+1,i+d+1);X[x++]=x2;int y2=min(2*n+1,j+d+1);Y[y++]=y2;}sort(X,X+x),sort(Y,Y+y);x=unique(X,X+x)-X,y=unique(Y,Y+y)-Y;for(int i=0;i<x;i++)for(int j=0;j<y;j++)s[i][j]=0;for(auto [i,j]:p[c]){int x1=lower_bound(X,X+x,max(1,i-d))-X;int y1=lower_bound(Y,Y+y,max(1,j-d))-Y;int x2=lower_bound(X,X+x,min(2*n+1,i+d+1))-X;int y2=lower_bound(Y,Y+y,min(2*n+1,j+d+1))-Y;s[x1][y1]++;s[x1][y2]--;s[x2][y1]--;s[x2][y2]++;}for(int i=1;i<x;i++){for(int j=1;j<y;j++){s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];}}for(int i=1;i<x;i++){for(int j=1;j<y;j++)s[i][j]=s[i][j]>0;}for(int i=1;i<x;i++){for(int j=1;j<y;j++){v[X[i]][Y[j]]+=s[i][j]-s[i-1][j]-s[i][j-1]+s[i-1][j-1];}}}for(int i=1;i<=2*n;i++){for(int j=1;j<=2*n;j++){v[i][j]+=v[i-1][j]+v[i][j-1]-v[i-1][j-1];if(ok[i][j]&&v[i][j]==m)return 1;}}return 0;
}
signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n>>m;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){cin>>a[i][j];ok[i+j][i-j+n]=1;p[a[i][j]].push_back({i+j,i-j+n});}int l=0,r=n;while(l<r){int mid=l+r>>1;if(check(mid))r=mid;else l=mid+1;}cout<<r;
}

费用流

在这里插入图片描述
有些题它明明靠的是网络流,但是需要满足特定的需求,我们可以利用费用流的特点去解决

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,M=1e6+10;
int n,m,S,T,h[N],e[M],ne[M],f[M],w[M];
int incf[N],pre[N],d[N],st[N],idx,q[N];
void add(int a,int b,int c,int d){e[idx]=b,f[idx]=c,w[idx]=d,ne[idx]=h[a],h[a]=idx++;e[idx]=a,f[idx]=0,w[idx]=-d,ne[idx]=h[b],h[b]=idx++;
}
bool spfa(){memset(d,-0x3f,sizeof d);memset(incf,0,sizeof incf);int hh=0,tt=1;q[0]=S,d[S]=0,incf[S]=1e9;while(hh!=tt){int t=q[hh++];if(hh==N)hh=0;st[t]=0;for(int i=h[t];~i;i=ne[i]){int ver=e[i];if(f[i]&&d[ver]<d[t]+w[i]){d[ver]=d[t]+w[i];pre[ver]=i;incf[ver]=min(incf[t],f[i]);if(!st[ver]){st[ver]=1;q[tt++]=ver;if(tt==N)tt=0;}}}}return incf[T]>0;
}
void EK(int &flow,int &cost){flow=cost=0;while(spfa()){int t=incf[T];flow+=t;cost+=t*d[T];for(int i=T;i!=S;i=e[pre[i]^1]){f[pre[i]]-=t;f[pre[i]^1]+=t;}}
}signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);memset(h,-1,sizeof h);
//     cin>>n>>m>>S>>T;
//     while(m--){
//         int a,b,c,d;
//         cin>>a>>b>>c>>d;
//         add(a,b,c,d);
//     }
//     int flow,cost;
//     EK(flow,cost);
//     cout<<flow<<" "<<cost;cin>>n>>m;S=0,T=N-1;for(int i=1;i<=n;i++)add(S,i,1,0);for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){char c;cin>>c;if(c=='1')add(i,j+n,1,0);}}for(int j=1;j<=m;j++){for(int x=1;x<=n;x++)add(j+n,T,1,x);}int flow,cost;EK(flow,cost);
//     cout<<"flow="<<flow<<" cost="<<cost<<endl;if(flow!=n){cout<<-1;return 0;}for(int u=1;u<=n;u++){for(int i=h[u];~i;i=ne[i]){int j=e[i];if(!f[i]&&j>n){cout<<j-n<<" ";break;}}}
}

决策单调性

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+10;
int n,m;
struct node{int w,q;bool operator<(const node&t)const{return w*(10000-t.q)<t.w*(10000-q);}
}a[N];
double f[21];
signed main(){ios::sync_with_stdio(0);cin.tie(0);cin>>n>>m;for(int i=1;i<=n;i++)cin>>a[i].w;for(int i=1;i<=n;i++)cin>>a[i].q;sort(a+1,a+1+n);for(int j=1;j<=m;j++)f[j]=-1e9;f[0]=0;for(int i=1;i<=n;i++){for(int j=m;j>=1;j--)f[j]=max(f[j],f[j-1]*a[i].q/10000+a[i].w);}cout<<fixed<<setprecision(10)<<f[m];
}

2020CCPC长春K题启发式合并

难度主要是那个放缩,理解了放缩的话,
就可以把可能的答案存进vector< int >g[x]里面,表示x的可能的答案
以后的题目可能换汤不换药,主要是找到怎么放缩式子或者快速找到可能的答案,只要是gcd都可以往这方面去考虑

题解传送门
题目传送门

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+10;
int n,m,p[N],sz[N],a[N];
ll ans;
vector<int>g[N];//g[i]表示i可能的答案,枚举i的约数存入进去
unordered_map<int,int>mp[N];
int find(int x){if(p[x]==x)return x;return p[x]=find(p[x]);
}
// a^b==gcd(a,b)有多少对
//a^b>=|a-b|>=gcd(a,b)void merge(int x,int y){x=find(x),y=find(y);if(x==y)return;if(sz[x]<sz[y])swap(x,y);for(auto [k,v]:mp[y]){for(auto t:g[k])if(mp[x].count(t))ans+=(ll)mp[x][t]*v;}for(auto [k,v]:mp[y])mp[x][k]+=v;mp[y].clear();p[y]=x;sz[x]+=sz[y];
}
void so(int x){for(int d=1;d*d<=x;d++){if(x%d)continue;int i=d,j=x/i,y;y=x-i;if((x^y)==__gcd(x,y)&&y>0)g[x].push_back(y);y=x+i;if((x^y)==__gcd(x,y)&&y<=2e5)g[x].push_back(y);if(i==j)continue;y=x-j;if((x^y)==__gcd(x,y)&&y>0)g[x].push_back(y);y=x+j;if((x^y)==__gcd(x,y)&&y<=2e5)g[x].push_back(y);}
}
signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);for(int i=1;i<=2e5;i++)so(i);/*for (int i = 1; i <= 200000; i++) {for (int j = i + i; j <= 200000; j += i) {if (gcd(j, i^j) == i)g[j].push_back(i^j);}}*/cin>>n>>m;for(int i=1;i<=n+m;i++)p[i]=i,sz[i]=1;for(int i=1;i<=n;i++)cin>>a[i],mp[i][a[i]]++;while(m--){int op,x;cin>>op;if(op==1){int v;cin>>x>>v;a[x]=v;mp[x][v]=1;}if(op==2){int y;cin>>x>>y;merge(x,y);}if(op==3){int v;cin>>x>>v;int u=find(x);for(auto t:g[a[x]])if(mp[u].count(t))ans-=mp[u][t];mp[u][a[x]]--;a[x]=v;for(auto t:g[a[x]])if(mp[u].count(t))ans+=mp[u][t];mp[u][a[x]]++;}cout<<ans<<'\n';}
}

2020CCPC长春F. Strange Memory(长链剖分/启发式合并)

https://codeforces.com/gym/102832/problem/F

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],n,x,m;
long long ans;
int dfn[N],L[N],R[N],o,u,v,sz[N],son[N];
vector<int>g[N];
int f[N*11][20][2];
//考虑每个节点的贡献,枚举子树
//f[i][j][k]表示权值为i第j为k的个数
void dfs(int u,int fa=0){sz[u]=1;dfn[++o]=u;L[u]=o;for(auto j:g[u]){if(j==fa)continue;dfs(j,u);sz[u]+=sz[j];if(sz[j]>sz[son[u]])son[u]=j;}R[u]=o;
}
void dsu(int u,int fa=0,int op=1){for(auto j:g[u]){if(j==fa||j==son[u])continue;dsu(j,u,1);}if(son[u])dsu(son[u],u,0);for(int i=0;i<20;i++)f[a[u]][i][u>>i&1]++;for(auto j:g[u]){if(j==fa||j==son[u])continue;for(int k=L[j];k<=R[j];k++){for(int i=0;i<20;i++){int p=a[u]^a[dfn[k]];int c=dfn[k]>>i&1;ans+=(1ll<<i)*f[p][i][1-c];}}for(int k=L[j];k<=R[j];k++){for(int i=0;i<20;i++)f[a[dfn[k]]][i][dfn[k]>>i&1]++;}}if(op){for(int j=L[u];j<=R[u];j++){int p=dfn[j];for(int i=0;i<20;i++)f[a[p]][i][p>>i&1]--;}}
}
signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n;for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<n;i++){cin>>u>>v;g[u].push_back(v);g[v].push_back(u);}dfs(1);dsu(1);cout<<ans;
}

倍增优化网络流建边(树链剖分也可以

#include<bits/stdc++.h>
using namespace std;
#define INF 1e9
const int N =(1e4+10)*21,M=N*10;
int h[N],e[M],f[M],ne[M],idx,d[N],cur[N],q[N],o;
int n,m,S,T;
void add(int a,int b,int c){e[idx]=b,f[idx]=c,ne[idx]=h[a],h[a]=idx++;e[idx]=a,f[idx]=0,ne[idx]=h[b],h[b]=idx++;
}
bool bfs()  // 创建分层图
{int hh = 0, tt = 0;memset(d, -1, sizeof d);q[0] = S, d[S] = 0, cur[S] = h[S];while (hh <= tt){int t = q[hh ++ ];for (int i = h[t]; ~i; i = ne[i]){int ver = e[i];if (d[ver] == -1 && f[i]){d[ver] = d[t] + 1;cur[ver] = h[ver];if (ver == T) return true;q[ ++ tt] = ver;}}}return false;  // 没有增广路
}int find(int u, int limit)  // 在残留网络中增广
{if (u == T) return limit;int flow = 0;for (int i = cur[u]; ~i && flow < limit; i = ne[i]){cur[u] = i;  // 当前弧优化int ver = e[i];if (d[ver] == d[u] + 1 && f[i]){int t = find(ver, min(f[i], limit - flow));if (!t) d[ver] = -1;f[i] -= t, f[i ^ 1] += t, flow += t;}}return flow;
}int dinic()
{int r = 0, flow;while (bfs()) while (flow = find(S, INF)) r += flow;return r;
}
typedef pair<int,int>PII;
vector<PII>g[N];
int fa[N][20],id[N][20],dep[N];
void dfs(int u,int F=0,int ID=0){fa[u][0]=F;id[u][0]=ID;for(int i=1;i<20;i++){fa[u][i]=fa[fa[u][i-1]][i-1];id[u][i]=++o;add(id[u][i],id[u][i-1],1e9);add(id[u][i],id[fa[u][i-1]][i-1],1e9);}dep[u]=dep[F]+1;for(auto t:g[u]){int j=t.first;int ID=t.second;if(j==F)continue;dfs(j,u,ID);}
}
void lca(int a,int b){if(dep[a]<dep[b])swap(a,b);for(int i=19;i>=0;i--){if(dep[fa[a][i]]>=dep[b]){add(o,id[a][i],1e9);a=fa[a][i];}}if(a==b)return;for(int i=19;i>=0;i--){if(fa[a][i]!=fa[b][i]){add(o,id[a][i],1e9);add(o,id[b][i],1e9);a=fa[a][i],b=fa[b][i];}}add(o,id[a][0],1e9),add(o,id[b][0],1e9);
}
signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);memset(h,-1,sizeof h);cin>>n>>m;S=1,T=2,o=2;for(int i=1;i<n;i++){int a,b,c;cin>>a>>b>>c;add(++o,T,c);g[a].push_back({b,o});g[b].push_back({a,o});}dfs(1);int sum=0;while(m--){int a,b,x,y;cin>>a>>b>>x>>y;if(x<y)continue;//很关键,一定要剔除在外,不能让sum加上这个sum+=x-y;add(S,++o,x-y);lca(a,b);}cout<<sum-dinic();
}

二分图博弈

/*二分图博弈
给出一张二分图和起始点 H
,A和B轮流操作,每次只能选与上个被选择的点(第一回合则是点
)相邻的点,且不能选择已选择过的点,无法选点的人输掉
。一个经典的二分图博弈模型是在国际象棋棋盘上,双方轮流移动一个士兵
,不能走已经走过的格子,问谁先无路可走。

这类模型其实很好处理。考虑二分图的最大匹配,如果最大匹配一定包含
,那么先手必胜,否则先手必败。
需要注意的是,如果采用Dinic,不要根据有没有 H
点建两次图。而是在建图时把涉及 H
点的边存下来,跑完第一次Dinic后再建这些边,第二次Dinic看有没有增加流量。
或者直接源点S向start点连一条容量为1的边,再跑一次dinic,如果flow还有,也就是说flow>0先手必胜
如果flow=0,说明起始点不是关键点是可有可无的,先手必败

题目大意:给出一个密码锁,两个人一起玩游戏,给出初始的密码,规定:

每一次都可以转动一个位置的数字一个单位
不可以转动到已经出现过的数字
不可以转动到被 ban 掉的数字
无法转动的人视为失败,问谁能获胜

对于此题而言,每次将数字的某个位置转动一个单位,其数位和的奇偶性会发生变化,从这里入手,将所有数字拆分成一张二分图

建图如下:

源点 -> 奇数:流量为 1
奇数 -> 偶数:如果数位和的绝对值相差 1 个单位:流量为 1
偶数 -> 汇点:流量为 1
先不建起点跑最大流,然后把起点加上,看看有没有增广路即可

*/

#include<iostream>
#include <cstring>
#include <cmath>
#include <map>
#include <vector>
#include <algorithm>
#include <set>
#define int ll
using namespace std;
typedef long long ll;
const int M = 2e6 + 5;
const int N = 2e5 + 5;
const int INF = 0x3f3f3f3f;
int tot,len;
int fac[]={1,10,100,1000,10000,100000,1000000}; 
int vis[N];
struct node
{int v,w,to;
} edge[M*2];
int pre[N],cnt,dep[N];
int S,T,z,head[N],sum,id;
int n,m,q[N],cur[N];
void add(int u,int v,int w)
{edge[cnt]= {v,w,head[u]};head[u]=cnt++;edge[cnt]= {u,0,head[v]};head[v]=cnt++;
}
bool bfs()
{for(int i=0; i<=T; i++)dep[i]=0;dep[S]=1;int l=0,r=1;q[r]=S;while(l<r){int u=q[++l];for(int i=head[u]; i!=-1; i=edge[i].to){int v=edge[i].v;if(!dep[v]&&edge[i].w)dep[v]=dep[u]+1,q[++r]=v;}}return dep[T];
}
int dfs(int u,int mi)
{int res=0;if(mi==0||u==T)return mi;for(int &i=cur[u]; i!=-1; i=edge[i].to){int v=edge[i].v;if(dep[u]+1==dep[v]&&edge[i].w){int minn=dfs(v,min(mi-res,edge[i].w));edge[i].w-=minn;edge[i^1].w+=minn;res+=minn;if(res==mi)return res;}}if(res==0) dep[u]=0;return res;
}
int dinic()
{ll res=0;while(bfs()){memcpy(cur,head,sizeof(head));
//        cout<<res<<endl;res+=dfs(S,INF);}return res;
}
int stF;
int getnum(int i){int ans=0;//cout<<i<<" ";while(i){ans += i%10;i/= 10;}//cout<<ans<<endl;return ans;
}void cal(int n){int index = 10, res,org = n;for(int i = 0; i<len;i++){res = n/fac[i];
//		n/=10;res%=10;int ub = (res+1)%10;int lb = (res-1+10)%10;
//		cout<<"len: "<<len<<endl;
//		cout<<org<<": "<<org-res*pow(10,i)+ub*pow(10,i)<<" "<<org-res*pow(10,i)+lb*pow(10,i)<<endl;if(!vis[(org-res*fac[i]+ub*fac[i])])add(org,org-res*fac[i]+ub*fac[i],INF);if(!vis[(org-res*fac[i]+lb*fac[i])])add(org,org-res*fac[i]+lb*fac[i],INF);}
}
signed main(){ios::sync_with_stdio(0);int t,st,mxflow;cin >> t;while(t--){memset(vis,0,sizeof vis);cin >> len >> n >> st;S = fac[len],T = S+1;
//		cout<<S<<" "<<T<<endl;cnt = 0;for(int i = 0; i<=T; i++) head[i] = -1;stF = getnum(st);stF &= 1;int tmp;
//		_set.insert(st);for(int i =0; i < n;i++){cin >> tmp;vis[tmp]=1;}for(int i = 0; i<S;i++){if(vis[i]) continue;if( (getnum(i)&1) == stF){cal(i);if(i != st) add(S,i,1);}else{add(i,T,1);	}}mxflow = dinic();add(S,st,1);mxflow=dinic();if(mxflow == 0) cout<<"Bob\n";else cout<<"Alice\n"; } 
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/24907.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

协议,序列化,反序列化,Json

文章目录 协议序列化和反序列化网络计算器protocol.hppServer.hppServer.ccClient.hppClient.cclog.txt通过结果再次理解通信过程 Json效果 协议 协议究竟是什么呢&#xff1f;首先得知道主机之间的网络通信交互的是什么数据&#xff0c;像平时使用聊天APP聊天可以清楚&#x…

迭代器模式(Iterator)

迭代器模式是一种行为设计模式&#xff0c;可以在不暴露底层实现(列表、栈或树等)的情况下&#xff0c;遍历一个聚合对象中所有的元素。 Iterator is a behavior design pattern that can traverse all elements of an aggregate object without exposing the internal imple…

机器学习常用Python库安装

机器学习常用Python库安装 作者日期版本说明Dog Tao2022.06.16V1.0开始建立文档 文章目录 机器学习常用Python库安装Anaconda简介使用镜像源配置 Pip简介镜像源配置 CUDAPytorch安装旧版本 TensorFlowGPU支持说明 DGL简介安装DGLLife RDKitscikit-multilearn Anaconda 简介 …

UEditorPlus v3.3.0 图片上传压缩重构,UI优化,升级基础组件

UEditor是由百度开发的所见即所得的开源富文本编辑器&#xff0c;基于MIT开源协议&#xff0c;该富文本编辑器帮助不少网站开发者解决富文本编辑器的难点。 UEditorPlus 是有 ModStart 团队基于 UEditor 二次开发的富文本编辑器&#xff0c;主要做了样式的定制&#xff0c;更符…

C++经典排序算法详解

目录 一、选择排序 二、冒泡排序 三、插入排序 一、选择排序 选择排序 选择排序&#xff08;Selection sort&#xff09;是一种简单直观的排序算法。它的工作原理是&#xff1a;第一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;存…

解决vite+vue3项目npm装包失败

报错如下&#xff1a; Failed to remove some directories [ npm WARN cleanup [ npm WARN cleanup D:\\V3Work\\v3project\\node_modules\\vue, npm WARN cleanup [Error: EPERM: operation not permitted, rmdir D:\V3Work\v3project\node_modules\vue\reactivity\…

嵌入式开发学习(STC51-13-温度传感器)

内容 通过DS18B20温度传感器&#xff0c;在数码管显示检测到的温度值&#xff1b; DS18B20介绍 简介 DS18B20是由DALLAS半导体公司推出的一种的“一线总线&#xff08;单总线&#xff09;”接口的温度传感器&#xff1b; 与传统的热敏电阻等测温元件相比&#xff0c;它是一…

关于Express 5

目录 1、概述 2、Express 5的变化 2.1 弃用或删除内容的列表&#xff1a; app.param&#xff08;name&#xff0c;fn&#xff09;名称中的前导冒号&#xff08;&#xff1a;&#xff09; app.del() app.param&#xff08;fn&#xff09; 复数方法名 res.json&#xff0…

Codeforces Round 890 (Div. 2) D. More Wrong(交互题 贪心/启发式 补写法)

题目 t(t<100)组样例&#xff0c;长为n(n<2000)的序列 交互题&#xff0c;每次你可以询问一个区间[l,r]的逆序对数&#xff0c;代价是 要在的代价内问出最大元素的位置&#xff0c;输出其位置 思路来源 neal Codeforces Round 890 (Div. 2) supported by Constructo…

Godot 4 源码分析 - Path2D与PathFollow2D

学习演示项目dodge_the_creeps&#xff0c;发现里面多了一个Path2D与PathFollow2D 研究GDScript代码发现&#xff0c;它主要用于随机生成Mob var mob_spawn_location get_node(^"MobPath/MobSpawnLocation")mob_spawn_location.progress randi()# Set the mobs dir…

【C语言】初阶完结练习题

&#x1f388;个人主页&#xff1a;库库的里昂 &#x1f390;CSDN新晋作者 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 ✨收录专栏&#xff1a;C语言初阶 ✨其他专栏&#xff1a;代码小游戏 &#x1f91d;希望作者的文章能对你有所帮助&#xff0c;有不足的地方请在评论…

Misc取证学习

文章目录 Misc取证学习磁盘取证工具veracryto挂载fat文件DiskGenius 磁盘取证例题[RCTF2019]disk 磁盘[](https://ciphersaw.me/ctf-wiki/misc/disk-memory/introduction/#_2)内存取证工具volatility 内存取证例题数字取证赛题0x01.从内存中获取到用户admin的密码并且破解密码 …

如何搭建一个成功的家具小程序

家具行业近年来发展迅猛&#xff0c;越来越多的消费者开始选择在小程序商城上购买家具。因此&#xff0c;制作一款家具小程序商城成为了许多家具商家的必然选择。那么&#xff0c;如何制作一款个性化、功能齐全的家具小程序商城呢&#xff1f;下面将为大家介绍一种简单且高效的…

观察者模式(C++)

定义 定义对象间的一种一对多(变化)的依赖关系&#xff0c;以便当一个对象(Subject)的状态发生改变时&#xff0c;所有依赖于它的对象都得到通知并自动更新。 ——《设计模式》GoF 使用场景 一个对象&#xff08;目标对象&#xff09;的状态发生改变&#xff0c;所有的依赖对…

Pytorch Tutorial【Chapter 3. Simple Neural Network】

Pytorch Tutorial【Chapter 3. Simple Neural Network】 文章目录 Pytorch Tutorial【Chapter 3. Simple Neural Network】Chapter 3. Simple Neural Network3.1 Train Neural Network Procedure训练神经网络流程3.2 Build Neural Network Procedure 搭建神经网络3.3 Use Loss …

【LeetCode】24.两两交换链表中的节点

题目 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4] 输出&#xff1a…

SQL-每日一题【1193. 每月交易 I】

题目 Table: Transactions 编写一个 sql 查询来查找每个月和每个国家/地区的事务数及其总金额、已批准的事务数及其总金额。 以 任意顺序 返回结果表。 查询结果格式如下所示。 示例 1: 解题思路 1.题目要求我们查找每个月和每个国家/地区的事务数及其总金额、已批准的事务数…

实验笔记之——Windows下的Android环境开发搭建

好久一段时间没有进行Android开发了&#xff0c;最新在用的电脑也没有了Android studio了。为此&#xff0c;本博文记录一下最近重新搭建Android开发的过程。本博文仅为本人学习记录用&#xff08;**别看&#xff09; 目录 安装Android Studio以及JDK JDK Android Studiio …

Java并发系列之七:ConcurrentHashMap

回顾HashMap 既然说到HashMap了&#xff0c;那么我们就先来简单总结一下HashMap的重点。 1.基本结构 HashMap存储的是存在映射关系的键值对&#xff0c;存储在被称为哈希表(数组链表/红黑树)的数据结构中。通过计算key的hashCode值来确定键值对在数组中的位置&#xff0c;假…

【机器学习】西瓜书学习心得及课后习题参考答案—第5章神经网络

笔记心得 5.1神经元模型——这是神经网络中最基本的成分。 5.2感知机与多层网络——由简单的感知机循序渐进引出多层前馈神经网络。 5.3误差逆传播算法——BP算法&#xff0c;迄今最成功的神经网络学习算法。算法如下&#xff08;公式参考西瓜书&#xff09; 停止条件与缓解…