做题纪要
Alice and Recoloring 1#
有一个很牛逼的转化,考虑一个点
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=505;
char s[N];
int c[N][N];
int a[N][N];
int sum[N][N];
signed main(){
int n,m;
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
for(int j=1;j<=m;j++){
if(s[j]=='B') c[i][j]=1;
else c[i][j]=0;
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[i][j]=(c[i][j]^c[i+1][j]^c[i][j+1]^c[i+1][j+1]);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
sum[i][j]+=a[i][j];
}
}
int ans=sum[n][m];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int w;
w=a[n][m]+a[i-1][j-1]+a[n][j-1]+a[i-1][m];
ans=min(ans,3+sum[n][m]-w+4-w);
}
}
printf("%lld",ans);
}
Alice and Recoloring 2#
转换和上道题一样,唯一不同的就是两次操作四比六次会比操作一优,所以操作四可以操作很多次,但还有一些其他性质需要挖掘:
-
若两次四操作为
和 则会改变四个 值,则可以用四次操作一代替,纵坐标相等横坐标不同同理,所以四操作不会出现在同一行同一列。 -
四操作假如
, , 不全为一,则会产生一次负贡献,需要用一代价的操作一代替(不可能是操作四,由👆可知),所以仅反转三个格子总代价为 ,可以用一代替,所以只有那三个格子均为一,才会进行操作四。
所以肯定是合法的操作四越多越好,为了求这个,也就是二分图最大匹配,考虑 Dinic ,左侧
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=600;
const int M=360000;
const int inf=0x3f3f3f3f3f;
char s[N];
int c[N][N];
int a[N][N];
int st,ed;
int head[M*2],ver[M*2],nex[M*2],edge[M*2],tot=1;
void add(int x,int y,int v){
ver[++tot]=y,nex[tot]=head[x],head[x]=tot,edge[tot]=v;
ver[++tot]=x,nex[tot]=head[y],head[y]=tot,edge[tot]=0;
}
int dep[M],cur[M];
int bfs(){
memset(dep,0,sizeof(dep));
dep[st]=1;
queue<int> q;
q.push(st);
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(dep[y] || edge[i]==0) continue;
dep[y]=dep[x]+1;
q.push(y);
}
}
if(dep[ed]) return 1;
else return 0;
}
int dfs(int x,int flow){
if(x==ed) return flow;
for(int i=cur[x];i;i=nex[i]){
cur[x]=i;
int y=ver[i];
if(dep[y]==dep[x]+1 && edge[i]){
int d=dfs(y,min(flow,edge[i]));
if(d>0){
edge[i]-=d;
edge[i^1]+=d;
return d;
}
}
}
return 0;
}
int Dinic(){
int ans=0;
while(bfs()){
for(int i=1;i<=ed;i++)
cur[i]=head[i];
while(int d=dfs(st,inf)){
ans+=d;
}
}
return ans;
}
signed main(){
int n,m;
scanf("%lld%lld",&n,&m);
int sum=0;
for(int i=1;i<=n;i++){
scanf("%s",s+1);
for(int j=1;j<=m;j++){
if(s[j]=='B') c[i][j]=1;
else c[i][j]=0;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j]=(c[i][j]^c[i+1][j]^c[i][j+1]^c[i+1][j+1]);
if(a[i][j]) sum++;
}
}
st=n+m+1,ed=st+1;
for(int i=1;i<n;i++) add(st,i,1);
for(int i=1;i<m;i++) add(n+i,ed,1);
for(int i=1;i<n;i++){
for(int j=1;j<m;j++){
if(a[i][j] && a[i][m] && a[n][j]){
add(i,n+j,1);
}
}
}
int cnt=Dinic();
int ans=0;
ans+=cnt*2;
int w=sum-cnt*3;
if(a[n][m] && cnt%2) ans--;
if(!a[n][m] && cnt%2) ans++;
printf("%lld",ans);
return 0;
}
[ABC324F] Beautiful Path#
题干要求
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2*1e5+10;
const long double eps=1e-15;
int head[N*2],ver[N*2],nex[N*2],tot=0;
long double edge[N*2];
void add(int x,int y,long double v){
ver[++tot]=y,nex[tot]=head[x],head[x]=tot,edge[tot]=v;
}
struct asd{
int x,y;
long double b,c;
}a[N];
int n,m;
long double dp[N];
bool dij(int p){
for(int i=1;i<=n;i++) dp[i]=-(1<<25);
dp[p]=0;
for(int x=1;x<n;x++){
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
dp[y]=max(dp[y],dp[x]+edge[i]);
}
}
return dp[n]>=0;
}
int check(long double k){
tot=0;
memset(head,0,sizeof(head));
for(int i=1;i<=m;i++){
int x=a[i].x,y=a[i].y;
long double w=a[i].b-k*a[i].c;
add(x,y,w);
}
return dij(1);
}
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=m;i++) scanf("%lld%lld%Lf%Lf",&a[i].x,&a[i].y,&a[i].b,&a[i].c);
long double l=0,r=21e9;
while(r-l>eps){
long double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
printf("%0.20Lf",l);
}
「KDOI-06-S」树上异或#
树形
然后考虑断边的操作 ,其实就是将当前不完整块个数为奇数的贡献计算出来,然后将其加到全部的
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=5*1e5+5;
const int mod=998244353;
int f[N][65][3];
long long a[N];
int head[N*2],ver[N*2],nex[N*2],tot=0;
void add(int x,int y){
ver[++tot]=y,nex[tot]=head[x],head[x]=tot;
}
int dfs(int x,int fa){
for(int i=1;i<=61;i++){
if(a[x]&(1ll<<(i-1))) f[x][i][1]=1;
else f[x][i][0]=1;
}
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(y==fa) continue;
dfs(y,x);
for(int j=1;j<=61;j++){
int f0=f[x][j][0],f1=f[x][j][1];
f[x][j][0]=1ll*(1ll*f0*f[y][j][0]%mod+1ll*f1*f[y][j][1]%mod)%mod;
f[x][j][1]=1ll*(1ll*f0*f[y][j][1]%mod+1ll*f1*f[y][j][0]%mod)%mod;
}
}
long long sum=0;
for(int i=1;i<=61;i++) sum=1ll*(1ll*sum+1ll*(1ll<<(i-1))%mod*f[x][i][1]%mod)%mod;
for(int i=1;i<=61;i++) f[x][i][0]=1ll*(1ll*f[x][i][0]+1ll*sum)%mod;
return sum;
}
signed main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=2;i<=n;i++){
int x;
scanf("%d",&x);
add(i,x),add(x,i);
}
long long ans=dfs(1,0);
printf("%lld",ans);
}
作者:bloss
出处:https://www.cnblogs.com/jinjiaqioi/p/17762864.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】