构造有感
CF1450C Errich-Tac-Toe
首先考虑限制是每三个格子不能相同
考虑染色,即为 \((i+j)\mod3\)
然后考虑每一种颜色,有一个一定大于\(\dfrac{n}{3}\)
对于剩下的 \(\dfrac{2n}{3}\),实际上一共有 \(6\) 种情况
\(6\)种情况一共会修改\(2n\),一定有一种方案是修改在\(\dfrac{n}{3}\)以下的
#include<bits/stdc++.h>
using namespace std;
const int MAXN=405;
int t;
int n;
int mp[MAXN][MAXN];
int fyouucupk[MAXN][MAXN];
char s[MAXN];
int solve(string x)
{
int cnp=0;
int byqflzh=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
int dw=(i+j)%3;
if((x[dw]!='0')&&(mp[i][j]))
{
fyouucupk[i][j]=x[dw]-'0';
}
else
{
fyouucupk[i][j]=mp[i][j];
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(mp[i][j])
{
byqflzh++;
cnp+=(mp[i][j]!=fyouucupk[i][j]);
}
}
}
// printf("%d %d\n",cnp,byqflzh);
return cnp*3<=byqflzh;
}
void print()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(fyouucupk[i][j]==1)
{
printf("X");
}
else if(fyouucupk[i][j]==2)
{
printf("O");
}
else
{
printf(".");
}
}
printf("\n");
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
memset(mp,0,sizeof(mp));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",s+1);
for(int j=1;j<=n;j++)
{
if(s[j]=='X')
{
mp[i][j]=1;
}
else if(s[j]=='O')
{
mp[i][j]=2;
}
}
}
if(solve("120"))
{
print();
}
else if(solve("210"))
{
print();
}
else if(solve("102"))
{
print();
}
else if(solve("201"))
{
print();
}
else if(solve("021"))
{
print();
}
else if(solve("012"))
{
print();
}
}
}
Mine Sweeper II
首先会发现地雷的数取决于相邻地雷与空格的边数
如果取反则总数不变
再考虑\(A与B\),\(A与(not\ B)\)
两个操作总数刚好为\(n*m\)
所以其中一个为\(\dfrac{n}{2}\)
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1005;
int n,m;
char s[MAXN];
int mpA[MAXN][MAXN];
int mpB[MAXN][MAXN];
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%s",s+1);
for(int j=1;j<=m;j++)
{
if(s[j]=='X')
{
mpA[i][j]=1;
}
else
{
mpA[i][j]=0;
}
}
}
for(int i=1;i<=n;i++)
{
scanf("%s",s+1);
for(int j=1;j<=m;j++)
{
if(s[j]=='X')
{
mpB[i][j]=1;
}
else
{
mpB[i][j]=0;
}
}
}
int tot1=0,tot2=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
{
if(mpA[i][j]!=mpB[i][j])
{
tot1++;
}
else
{
tot2++;
}
}
}
if(tot1*2<=n*m)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(mpA[i][j]==1)
{
printf("X");
}
else{
printf(".");
}
}
printf("\n");
}
return 0;
}
if(tot2*2<=n*m)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if((mpA[i][j]^1)==1)
{
printf("X");
}
else{
printf(".");
}
}
printf("\n");
}
}
}
CF1364D Ehab's Last Corollary
考虑一些\(DFS树\)性质
首先考虑环的条件,我们可以在\(DFS\)的时判环
对于无法满足所有环,瞎搞即可
#include<bits/stdc++.h>
using namespace std;
const int MAXN=3e5+5;
int n,m,k;
vector<int>g[MAXN];
int x,y;
int dfn[MAXN];
int cnt_dfn;
int deep[MAXN];
int fa[MAXN];
void dfs(int x,int f)
{
dfn[x]=++cnt_dfn;
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i];
if(v==f)
{
continue;
}
if(dfn[v])
{
// printf("%d %d %d\n",x,v,deep[x]-deep[v]+1);
if(dfn[v]<dfn[x])
{
int df=deep[x]-deep[v]+1;
if(df<=k)
{
printf("2\n");
int nx=x;
printf("%d\n",df);
while(nx!=v)
{
printf("%d ",nx);
nx=fa[nx];
}
printf("%d",v);
exit(0);
}
}
}
else
{
deep[v]=deep[x]+1;
fa[v]=x;
dfs(v,x);
}
}
}
void DFS(int x,int f)
{
dfn[x]=++cnt_dfn;
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i];
if(v==f)
{
continue;
}
if(dfn[v])
{
if(dfn[v]<dfn[x]){
int df=deep[x]+deep[v]+1;
if(df>k)
{
int nx=x;
int op=0,tot=0;
while(nx!=v)
{
if((!op)&&(tot<(k+1)/2))
{
tot++;
printf("%d ",nx);
}
op^=1;
nx=fa[nx];
}
if((!op)&&(tot<(k+1)/2))
{
tot++;
printf("%d ",v);
}
exit(0);
}
}
}
else
{
deep[v]=deep[x]+1;
fa[v]=x;
DFS(v,x);
}
}
}
int main()
{
scanf("%d %d %d",&n,&m,&k);
for(int i=1;i<=m;i++){
scanf("%d %d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
dfs(1,1);
printf("1\n");
int aim=(k+1)/2;
if(m==n-1)
{
int tot1=0;
for(int i=1;i<=n;i++){
if(deep[i]%2==0)
{
tot1++;
}
}
if(tot1*2>=n)
{
tot1=0;
for(int i=1;i<=n;i++)
{
if(deep[i]%2==0)
{
tot1++;
printf("%d ",i);
}
if(tot1==aim)
{
break;
}
}
}
else
{
tot1=0;
for(int i=1;i<=n;i++)
{
if(deep[i]%2==1)
{
tot1++;
printf("%d ",i);
}
if(tot1==aim)
{
break;
}
}
}
}
memset(dfn,0,sizeof(dfn));
cnt_dfn=0;
DFS(1,1);
}
[IOI2019]景点划分
首先考虑\(a\leq b \leq c\) ,因为大小无所谓
因为要有两个联通块,所以,可以只需要划分两个最小的联通块,剩下的其实可以全部放在另一个联通块
问题转换为将图划分为两个联通块\((Siz_{min}=a,Siz_{max}=b,a\leq b \leq \dfrac{n}{2})\)和散点
再考虑将图划分为\(DFS序树\),考虑先处理树,如果树满足则一定可以转化到树上
问题即为将图划分为两个联通块\((Siz_{min}\geq a,Siz_{max}\geq b,a\leq b \leq \dfrac{n}{2})\),因此我们要尽量平均
考虑树的重心,重心下的连通块每一个都小于\(\dfrac{n}{2}\),如果不是,那当前状态下的重心一定不是最优
\(设重心上方的点集为T,下方儿子即为S_i\)
\(若Maximize(T,S_i)\geq a\)
重心下的最大的联通块大小一定小于\(\dfrac{n}{2}\),所以选择一块剩余部分一定可以满足\(B\)的条件
\(若Maximize(T,S_i)\leq a\)
因为\(DFS\)序的性质,返祖边只能手冲\(S\)连到\(T\),\(S\)之间不能连边
然后通过返祖边不断扩大\(T\),最后\(T\)的大小也不会超过\(2a\),而\(2a+b<a+b+c<n,n-2a>b\),所以这样加是满足的
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+5;
int n,m;
struct Edge{
int x,y;
}edge[MAXN];
vector<int>g[MAXN];
int x,y;
int a,b,c;
vector<pair<int,int> >TEACHER;
string PHYSICAL()
{
TEACHER.push_back(make_pair(a,1));
TEACHER.push_back(make_pair(b,2));
TEACHER.push_back(make_pair(c,3));
sort(TEACHER.begin(),TEACHER.end());
a=TEACHER[0].first;
b=TEACHER[1].first;
return "Quan bu qu si";
}
int dfn[MAXN];
int Chemistry_teachersb;
vector<int>G1[MAXN];
vector<int>G2[MAXN];
int Fa[MAXN];
void dfs(int x,int f)
{
dfn[x]=++Chemistry_teachersb;
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i];
int w=g[x][i];
if(v==f)
{
continue;
}
if(dfn[v])
{
if(dfn[v]<dfn[x])
{
G2[x].push_back(v);G2[v].push_back(x);
}
}
else
{
G1[x].push_back(v);
G1[v].push_back(x);
Fa[v]=x;
dfs(v,x);
}
}
}
int Siz[MAXN];
int LSYISSB=0x3f3f3f3f;
int ZSJISSB;
void IAMSB(int x,int f){
Siz[x]=1;
int ZSLISSB=0;
for(int i=0;i<G1[x].size();i++)
{
int v=G1[x][i];
if(v==f)
{
continue;
}
IAMSB(v,x);
Siz[x]=Siz[x]+Siz[v];
ZSLISSB=max(ZSLISSB,Siz[v]);
}
ZSLISSB=max(ZSLISSB,n-Siz[x]);
if(ZSLISSB<LSYISSB)
{
LSYISSB=ZSLISSB;
ZSJISSB=x;
}
}
int Heart;
int AVID[MAXN];
vector<int>S[MAXN];
int cnts=0;
int AAA[MAXN];
int Cnta=0;
void FIND(int x,int f)
{
S[cnts].push_back(x);
for(int i=0;i<G1[x].size();i++)
{
int v=G1[x][i];
if(v==f)
{
continue;
}
FIND(v,x);
}
}
int Symbol[MAXN];
int Clor[MAXN];
void Find(int x,int f,int clo,int lit)
{
if(lit==x)
{
return;
}
if(Symbol[x])
{
return;
}
// printf("%d\n",x);
Symbol[x]=clo;
for(int i=0;i<G1[x].size();i++)
{
int v=G1[x][i];
if(v==f)
{
continue;
}
Find(v,x,clo,lit);
}
}
int cnta=0;
int cntb=0;
void FFind(int x,int clo)
{
if(Clor[x])
{
return;
}
if(Symbol[x]==clo)
{
if(clo==1)
{
if(cnta<a)
{
Clor[x]=1;
cnta++;
}
else
{
return;
}
}
else if(clo==2)
{
if(cntb<b){
Clor[x]=2;
cntb++;
}
else
{
return;
}
}
}
else
{
return;
}
for(int i=0;i<G1[x].size();i++)
{
int v=G1[x][i];
FFind(v,clo);
}
for(int i=0;i<G2[x].size();i++)
{
int v=G2[x][i];
FFind(v,clo);
}
}
int main()
{
// freopen("4-27.in","r",stdin);
scanf("%d %d",&n,&m);
scanf("%d %d %d",&a,&b,&c);
string Meaningless1=PHYSICAL();
for(int i=1;i<=m;i++){
scanf("%d %d",&x,&y);
x++;
y++;
g[x].push_back(y);
g[y].push_back(x);
}
dfs(1,0);
IAMSB(1,0);
Heart=ZSJISSB;
int nOwx=Heart;
nOwx=Fa[nOwx];
while(nOwx)
{
AVID[nOwx]=1;
nOwx=Fa[nOwx];
}
for(int i=0;i<G1[Heart].size();i++)
{
int v=G1[Heart][i];
if(v==Fa[Heart])
{
continue;
}
++cnts;
FIND(v,Heart);
}
int Maxs=n-Siz[Heart];
//int FUCKYZK;
int Point=0;
for(int i=1;i<=cnts;i++)
{
if(Maxs<S[i].size())
{
Maxs=S[i].size();
Point=i;
}
}
//printf("%d %d\n",Point,Maxs);
if(Maxs>=a)
{
if(Point==0)
{
Find(1,0,1,Heart);
//
Find(Heart,Fa[Heart],2,0);
FFind(1,1);
FFind(Heart,2);
}
else
{
// printf("?");
Find(S[Point][0],Heart,1,0);
Find(1,0,2,Heart);
Find(Heart,Fa[Heart],2,0);
FFind(S[Point][0],1);
FFind(1,2);
//printf("-23");
// printf("%d %d\n",cnta,cntb);
}
for(int i=1;i<=n;i++)
{
if(Clor[i]==1)
{
printf("%d ",TEACHER[0].second);
}
else if(Clor[i]==2)
{
printf("%d ",TEACHER[1].second);
}
else
{
printf("%d ",TEACHER[2].second);
}
}
}
else
{
Find(1,0,1,Heart);
int Nows=n-Siz[Heart];
int zdskgs=0;
for(int xsh=1;xsh<=n;xsh++)
{
if(Symbol[xsh]==1)
{
zdskgs++;
}
}
// printf("%d %d wrnm\n",Nows,zdskgs);
for(int i=1;i<=cnts;i++)
{
for(int j=0;j<S[i].size();j++){
int Son=S[i][j];
for(int k=0;k<G2[Son].size();k++)
{
int LH=G2[Son][k];
if(AVID[LH])
{
AAA[i]=1;
break;
}
}
}
if(AAA[i])
{
Nows+=S[i].size();
for(int j=0;j<S[i].size();j++){
int Son=S[i][j];
Symbol[Son]=1;
}
zdskgs=0;
for(int xsh=1;xsh<=n;xsh++)
{
if(Symbol[xsh]==1)
{
zdskgs++;
}
}
// printf("%d %d %d wrnm\n",zdskgs,Nows,S[i].size());
if(Nows>=a)
{
for(int lf=1;lf<=n;lf++)
{
if(Symbol[lf]!=1)
{
Symbol[lf]=2;
}
}
zdskgs=0;
for(int xsh=1;xsh<=n;xsh++)
{
if(Symbol[xsh]==1)
{
zdskgs++;
}
}
// printf("%dsdhgse\n",zdskgs);
FFind(1,1);
// printf("%d\n",cnta);
FFind(Heart,2);
// printf("%d %d\n",cnta,cntb);
for(int ih=1;ih<=n;ih++)
{
if(Clor[ih]==1)
{
printf("%d ",TEACHER[0].second);
}
else if(Clor[ih]==2)
{
printf("%d ",TEACHER[1].second);
}
else
{
printf("%d ",TEACHER[2].second);
}
}
return 0;
}
}
}
for(int i=1;i<=n;i++)
{
printf("0 ");
}
}
// int TS=n-Siz[Heart];
//// printf("%d\n",Heart);
// int ILH=TS;
// int IXF=0;
// for(int i=1;i<=cnts;i++){
// /// ILH=max(ILH,S[i].size());
// if(S[i].size()>ILH)
// {
// ILH=S[i].size();
// IXF=i;
// }
// }
// if(ILH>=a)
// {
// if(IXF==0){
// Cnta=0;
// REFIND(1);
// Cntb=0;
//
// RRRFIND(Heart);
// for(int i=1;i<=n;i++)
// {
// if(Symbol[i]==1)
// {
// printf("%d ",TEACHER[0].second);
// }
// else if(Symbol[i]==2)
// {
// printf("%d ",TEACHER[1].second);
// }
// else
// {
// printf("%d ",TEACHER[2].second);
// }
// }
// }
// else
// {
// // printf("%d--\n",S[IXF][0]);
// Cnta=0;
// RRFIND(S[IXF][0]);
// Cntb=0;
// // printf("---%d\n",Heart);
// RRRFIND(Heart);
// //?????
// for(int i=1;i<=n;i++)
// {
// if(Symbol[i]==1)
// {
// printf("%d ",TEACHER[0].second);
// }
// else if(Symbol[i]==2)
// {
// printf("%d ",TEACHER[1].second);
// }
// else
// {
// printf("%d ",TEACHER[2].second);
// }
// }
// }
// return 0;
// }
// int IDSY=TS;
// REFIND(1);
// for(int i=1;i<=cnts;i++)
// {
// for(int j=0;j<S[i].size();j++){
// int Son=S[i][j];
// for(int k=0;k<G2[Son].size();k++)
// {
// int LH=G2[Son][k];
// if(AVID[LH])
// {
// AAA[i]=1;
// break;
// }
// }
// }
// if(AAA[i])
// {
//
//
//
// if(IDSY+S[i].size()>=a)
// {
// Cnta=IDSY;
// RRFIND(S[i][0]);
// Cntb=0;
// RRRFIND(Heart);
// for(int igg=1;igg<=n;igg++)
// {
// if(Symbol[igg]==1)
// {
// printf("%d ",TEACHER[0].second);
// }
// else if(Symbol[igg]==2)
// {
// printf("%d ",TEACHER[1].second);
// }
// else
// {
// printf("%d ",TEACHER[2].second);
// }
// }
// return 0;
// }
// else
// {
// IDSY+=S[i].size();
// for(int j=0;j<S[i].size();j++){
// int Son=S[i][j];
// Symbol[Son]=1;
// }
// }
// }
// }
}
CF1391E Pairs of Pairs
首先建一棵DFS树,令\(k=\lceil\dfrac{n}{2}\rceil\)
然后分为两类\(dep< k\)与\(dep\ge k\)
\(dep \ge k\)说明存在一条路径大于k
\(dep<k\)说明同一深度的两点可以互相匹配,就算个数为偶数也可以满足
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e6+5;
int t;
int n,m;
vector<int>g[MAXN],Rec[MAXN];
int x,y;
int cnt_dfn;
int dep[MAXN];
int dfn[MAXN];
vector<int>MAXD,D;
void dfs(int x,int f)
{
dfn[x]=++cnt_dfn;
D.push_back(x);
if(D.size()>=((n%2==0)?(n/2):(n/2+1))&&MAXD.size()==0)
{
MAXD=D;
}
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i];
if(v==f)
{
continue;
}
if(dfn[v])
{
if(dfn[v]<dfn[x])
{
}
}
else
{
dep[v]=dep[x]+1;
dfs(v,x);
}
}
D.pop_back();
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&m);
cnt_dfn=0;
for(int i=1;i<=n;i++)
{
dfn[i]=0;
g[i].clear();
Rec[i].clear();
}
for(int i=1;i<=m;i++)
{
scanf("%d %d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
MAXD.clear();
D.clear();
dep[1]=1;
dfs(1,0);
//int MAXD=0;
for(int i=1;i<=n;i++)
{
//MAXD=max(MAXD,dep[i]);
Rec[dep[i]].push_back(i);
}
if(MAXD.size()>=((n%2==0)?(n/2):(n/2+1)))
{
printf("PATH\n");
printf("%d\n",MAXD.size());
for(int i=0;i<MAXD.size();i++)
{
printf("%d ",MAXD[i]);
}
printf("\n");
}
else
{
vector<pair<int,int> >RRR;
for(int i=1;i<=n;i++)
{
if(Rec[i].size()>=2)
{
for(int j=0;j<Rec[i].size()&&j+1<Rec[i].size();j+=2)
{
RRR.push_back(make_pair(Rec[i][j],Rec[i][j+1]));
}
}
}
printf("PAIRING\n");
printf("%d\n",RRR.size());
for(int i=0;i<RRR.size();i++)
{
printf("%d %d\n",RRR[i].first,RRR[i].second);
}
// printf("\n");
}
}
}
CF1103C Johnny Solving
首先建一棵DFS树
分为两类\(dep< \lceil\dfrac{n}{k}\rceil\)与\(dep\ge \lceil\dfrac{n}{k}\rceil\)
大于等于的可以直接选路径
小于的说明叶子个数大于k
因为\(dep[leaf]<\lceil\dfrac{n}{k}\rceil\),如果\(|leaf|<k\),则\(\sum dep[leaf]<n\),而实际上每条边都会被统计,所以矛盾
由一个叶子一定能构成环,这样也不会包含
具体就是两个祖先A,B
如果\(dep[A]-dep[leaf]+1\ mod\ 3=0\and dep[B]-dep[leaf]+1\ mod\ 3=0\)
则\(dep[A]-dep[B] \mod 3=0\)
所以可以从A走到B
#include<bits/stdc++.h>
using namespace std;
const int MAXN=3e5+5;
int k;
int n,m;
vector<int>g[MAXN],Rec[MAXN];
int x,y;
int cnt_dfn;
int dep[MAXN];
int dfn[MAXN];
int Fa[MAXN];
int cnt_cycle;
vector<int>Leaf;
void dfs(int x,int f)
{
dfn[x]=++cnt_dfn;
bool af=0;
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i];
if(v==f)
{
continue;
}
if(dfn[v])
{
if(dfn[v]<dfn[x])
{
}
}
else
{
af=1;
Fa[v]=x;
dep[v]=dep[x]+1;
dfs(v,x);
}
}
if(!af)
{
Leaf.push_back(x);
}
}
int main()
{
scanf("%d %d %d",&n,&m,&k);
for(int i=1;i<=m;i++)
{
scanf("%d %d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
dep[1]=1;
dfs(1,0);
int MAXD=0;
int cnm=0;
for(int i=1;i<=n;i++)
{
if(dep[i]>MAXD)
{
MAXD=dep[i];
cnm=i;
}
// MAXD=max(MAXD,dep[i]);
}
if(MAXD>=((n%k==0)?(n/k):(n/k+1)))
{
printf("PATH\n");
printf("%d\n",MAXD);
int Now=cnm;
while(Now)
{
printf("%d ",Now);
Now=Fa[Now];
}
}
else
{
printf("CYCLES\n");
for(int i=0;i<k;i++)
{
int x=Leaf[i];
if(cnt_cycle!=k)
{
++cnt_cycle;
int Poi=0;
int A=g[x][Poi];
while(A==Fa[x])
{
++Poi;
A=g[x][Poi];
}
++Poi;
int B=g[x][Poi];
while(B==Fa[x])
{
++Poi;
B=g[x][Poi];
}
int DA=(dep[x]-dep[A]+1);
int DB=(dep[x]-dep[B]+1);
vector<int>RRRR;
if((DA%3==0)&&(DB%3==0))
{
if(dep[A]<dep[B])
{
swap(A,B);
}
RRRR.push_back(x);
int Now=A;
while(Now!=Fa[B])
{
RRRR.push_back(Now);
Now=Fa[Now];
}
// Rec[cnt_cycle]=RRRR;
}
else if((DA%3)!=0)
{
int Now=x;
while(Now!=Fa[A])
{
RRRR.push_back(Now);
Now=Fa[Now];
}
// Rec[cnt_cycle]=RRRR;
}
else if((DB%3)!=0)
{
int Now=x;
while(Now!=Fa[B])
{
RRRR.push_back(Now);
Now=Fa[Now];
}
// Rec[cnt_cycle]=RRRR;
}
printf("%d\n",RRRR.size());
for(int dd=0;dd<RRRR.size();dd++)
{
printf("%d ",RRRR[dd]);
}
printf("\n");
}
}
}
}
CF1450E Capitalism
差分约束
主要是\(b=0\)的边
我们暂时转化为\(|a_i-a_j|\leq 1\)
这样整张图为无向图
然后先判负环
然后再判奇环(一条边相当于+1或-1,如果是奇数就无法得到原数)
这样,对于一条边的两个点\(U,V\),一定不会相同,因为如果相同,设\(d_U=d_V\),则\(dis_U+dis_V\)为偶数,边数为奇数即为奇环(负边与正边抵消)
后面就是差分约束
#include<bits/stdc++.h>
using namespace std;
const int MAXN=205;
int n;
int m;
struct Edge{
int v;
int val;
};
vector<Edge>g[MAXN];
int f[MAXN][MAXN];
void Add(int u,int v,int val)
{
Edge XN;
XN.v=v;
XN.val=val;
g[u].push_back(XN);
//f[u][v]=val;
}
int vis[MAXN];
int tot[MAXN];
int dis[MAXN];
bool spfa(int s)
{
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(tot,0,sizeof(tot));
dis[s]=0;
queue<int>q;
q.push(s);
vis[s]=1;
while(q.size())
{
int temp=q.front();
if(tot[temp]>n)
{
return 0;
}
tot[temp]++;
q.pop();
vis[temp]=0;
for(int i=0;i<g[temp].size();i++)
{
int v=g[temp][i].v;
int w=g[temp][i].val;
if(dis[v]>dis[temp]+w)
{
dis[v]=dis[temp]+w;
if(vis[v])
{
continue;
}
vis[v]=1;
q.push(v);
}
}
}
return 1;
}
int x,y,z;
int Clor[MAXN];
void dfs(int x,int clor)
{
if(Clor[x])
{
if(Clor[x]!=clor)
{
printf("NO\n");
exit(0);
}
return;
}
Clor[x]=clor;
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i].v;
dfs(v,(clor==1)?2:1);
}
}
int main()
{
//memset(f,0x3f,sizeof(f));
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&x,&y,&z);
if(z==1)
{
Add(x,y,1);
Add(y,x,-1);
}
else
{
Add(x,y,1);
Add(y,x,1);
}
}
for(int i=1;i<=n;i++)
{
if(!spfa(i))
{
printf("NO");
return 0;
}
else
{
for(int j=1;j<=n;j++)
{
f[i][j]=dis[j];
}
}
}
dfs(1,1);
int Maxi=0;
int MMM=0;
for(int i=1;i<=n;i++)
{
int Maxis=0;
int Mini=0x3f3f3f3f;
for(int j=1;j<=n;j++)
{
Maxis=max(f[i][j],Maxis);
Mini=min(f[i][j],Mini);
}
int sf=Maxis-Mini;
if(sf>Maxi){
Maxi=sf;
MMM=i;
}
for(int j=1;j<=n;j++)
{
f[i][j]=(f[i][j]-Mini);
}
}
printf("YES\n");
printf("%d\n",Maxi);
for(int i=1;i<=n;i++)
{
printf("%d ",f[MMM][i]);
}
}
CF1592F1 Alice and Recoloring 1
首先\((n,1)\)与\((1,m)\)的操作是用不上的(\((1,1)\)的操作先覆盖\([(1,1),(x,m)]\)再覆盖\([(1,1),(x,y)]\))
设0为B,目标为全0
如果不考虑\((n,m)\)的操作
为了让花费最小,肯定一个点不会重复操作
然后判断一个点在最小的情况下是否会被覆盖
考虑二维差分(把矩阵倒着看)
\(F[i][j]=a[i+1][j]\ xor\ a[i][j+1]\ xor\ a[i+1][j+1]\)
这样修改\(F(x,y)\)等价于区间修改
然后可以确定修改的方案
最后操作四特判
#include<bits/stdc++.h>
using namespace std;
const int MAXN=505;
int n,m;
char s[MAXN];
int mp[MAXN][MAXN];
int zfx[15]={1,0,1};
int zfy[15]={0,1,1};
int NYH[MAXN][MAXN];
signed main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%s",s+1);
for(int j=1;j<=m;j++)
{
if(s[j]=='B')
{
mp[i][j]=1;
}
else
{
mp[i][j]=0;
}
NYH[i][j]=mp[i][j];
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
for(int k=0;k<3;k++)
{
int nx=i+zfx[k];
int ny=j+zfy[k];
if(nx>=1&&ny>=1&&nx<=n&&ny<=m)
{
NYH[i][j]^=mp[nx][ny];
}
}
}
}
int Res=0;
int f=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
Res+=NYH[i][j];
if((NYH[i-1][j-1])&&(NYH[n][m])&&(NYH[n][j-1])&&(NYH[i-1][m]))
{
f=1;
}
}
}
printf("%d\n",Res-f);
}
CF1521E Nastia and a Beautiful Matrix
考虑构造成
的形式,其中\((*)\)不填
观察矩阵,实际上\((*)\)就是\((i\bmod2=0,j\bmod2=0)\)的点
而\((i\bmod2=1,j\bmod2=1)\)没有限制,相邻\((i+j)\bmod2=1\)的点不该相同
填色序列为每种颜色按大小排序
先填\((i\bmod 2=1,j\bmod 2=0)\),再填\((i\bmod 2=1,j\bmod 2=1)\)
最后填\((i\bmod 2=2,j\bmod 2=1)\)
我们考虑无解的情况(空格过少或每一种个数多了)
所以有解必须满足
\(n^2-(\lfloor\dfrac{n}{2}\rfloor)^2\geq m且Max\leq\dfrac{n}{2}\)
因为最大颜色的不会冲突,所以考虑填色序列相同颜色的距离一定小于\(\lfloor\dfrac{n}{2}\rfloor\)
顺序问题(感性理解就是中间有\(\lfloor\dfrac{n}{2}\rfloor\)空档)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN=1e5+5;
int t;
int m,k;
int a[MAXN];
int Res[505][505];
pair<int,int>R[MAXN];
int zfx[15]={1,1,-1,-1};
int zfy[15]={1,-1,1,-1};
int Maxi=0;
void RR(int Mid)
{
for(int i=1;i<=k;i++)
{
R[i].first=a[i];
R[i].second=i;
}
sort(R+1,R+1+k);
int poi=k;
memset(Res,0,sizeof(Res));
for(int i=1;i<=Mid;i++)
{
for(int j=1;j<=Mid;j++)
{
if(i&1)
{
if(j%2==0)
{
while(poi&&R[poi].first==0)
{
poi--;
}
if(!poi)
{
continue;
}
Res[i][j]=R[poi].second;
R[poi].first--;
}
}
}
}
for(int i=1;i<=Mid;i++)
{
for(int j=1;j<=Mid;j++)
{
if(i&1)
{
if(j&1)
{
while(poi&&R[poi].first==0)
{
poi--;
}
if(!poi)
{
continue;
}
Res[i][j]=R[poi].second;
R[poi].first--;
}
}
}
}
for(int i=1;i<=Mid;i++)
{
for(int j=1;j<=Mid;j++)
{
if(i%2==0)
{
if(j&1)
{
while(poi&&R[poi].first==0)
{
poi--;
}
if(!poi)
{
continue;
}
Res[i][j]=R[poi].second;
R[poi].first--;
}
}
}
}
while(poi&&R[poi].first==0)
{
poi--;
}
if(!poi)
{
return;
}
return;
}
bool check(int n) {
if((n+1)/2*n>=Maxi&&n*n-(n/2)*(n/2) >=m) {
return 1;
}
return 0;
}
signed main()
{
scanf("%lld",&t);
while(t--)
{
Maxi=0;
scanf("%lld %lld",&m,&k);
for(int i=1;i<=k;i++)
{
scanf("%lld",&a[i]);
Maxi=max(Maxi,a[i]);
}
int l=(1);
int r=m;
int key;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid)){
key=mid;
r=mid-1;
}
else
{
l=mid+1;
}
}
printf("%lld\n",key);
RR(key);
for(int i=1;i<=key;i++)
{
for(int j=1;j<=key;j++)
{
int fg=Res[i][j];
printf("%lld ",fg);
}
printf("\n");
}
}
}