%%%KSkun大佬
话说明明是网络流……这题竟然还有打表找规律和纯贪心AC的……都是神犇啊……
来说一下如何建图。首先把每一个点拆成$X_i$和$Y_i$,然后$S$向$X_i$连一条容量为$1$的边,$Y_i$向$T$连一条容量为$1$的边。对于能和它组成完全平方数的点,从$A_j$向$B_i$连一条容量为$1$的边
然后考虑一下,加球不会导致柱子减少,所以可以枚举球数,然后每次加一个球,并跑一次最大流。如果新加入的球是能加到某一个柱子中的,那么这一次跑最大流是能得到新流的,只要能一直得到新流就一直加,当不能的时候,将柱子数加一(即将这一个球放到新的柱子上)
当柱子数等于$n+1$的时候退出,因为第$n+1$根柱子是刚被加的,所以在放最后一个球之前,所有的球都能放在$n$根柱子中,那么当前的球数减一就是答案
然后考虑一下怎么求方案。对于每一个点,我们可以定义$X_i=i*2,Y_i=i*2+1$,那么可以保证任意两个点的$X_i$和$Y_i$不会重复,且不管在哪一个点,除以二之后就是原来的点。那么我们可以在跑$dfs$的时候,把每一个可以往下走增广路的点连边(这就说明他们相加是完全平方数,可以放在同一个柱子里),那么就可以形成一个类似链表的东西。记录一下每一根柱子一开始放的球,然后沿着链表去找这个柱子上有哪些球就可以了
1 //minamoto 2 #include3 #include 4 #include 5 #include 6 #include 7 #include 8 using namespace std; 9 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)10 char buf[1<<21],*p1=buf,*p2=buf;11 inline int read(){12 #define num ch-'0'13 char ch;bool flag=0;int res;14 while(!isdigit(ch=getc()))15 (ch=='-')&&(flag=true);16 for(res=num;isdigit(ch=getc());res=res*10+num);17 (flag)&&(res=-res);18 #undef num19 return res;20 }21 char sr[1<<21],z[20];int C=-1,Z;22 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}23 inline void print(int x){24 if(C>1<<20)Ot();25 while(z[++Z]=x%10+48,x/=10);26 while(sr[++C]=z[Z],--Z);27 }28 const int inf=0x3f3f3f3f,N=100005,M=400005;29 int head[N],Next[M],ver[M],edge[M],tot=1,Pre[N];30 inline void add(int u,int v,int e){31 ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e;32 ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=0;33 }34 int dep[N],s,t;35 int n,m,cnt;36 queue q;37 bool bfs(){38 memset(dep,-1,sizeof(dep));39 dep[s]=0,q.push(s);40 while(!q.empty()){41 int u=q.front();q.pop();42 for(int i=head[u];i;i=Next[i]){43 int v=ver[i];44 if(dep[v]<0&&edge[i])45 dep[v]=dep[u]+1,q.push(v);46 }47 }48 return ~dep[t];49 }50 int dfs(int u,int limit){51 if(!limit||u==t) return limit;52 int flow=0,f;53 for(int i=head[u];i;i=Next[i]){54 int v=ver[i];55 if(dep[v]==dep[u]+1&&(f=dfs(v,min(limit,edge[i])))){56 flow+=f,limit-=f;57 edge[i]-=f,edge[i^1]+=f;58 Pre[u>>1]=v>>1;59 if(!limit) break;60 }61 }62 return flow;63 }64 int dinic(){65 int flow=0;66 while(bfs()) flow+=dfs(s,inf);67 return flow;68 }69 bool vis[N];int w[65];70 int main(){71 n=read();72 s=0,t=10005;73 while(m<=n){74 ++cnt;75 add(s,cnt<<1,1),add(cnt<<1|1,t,1);76 for(int i=sqrt(cnt)+1;i*i<(cnt<<1);++i) add((i*i-cnt)<<1,cnt<<1|1,1);77 int s=dinic();78 if(!s) w[++m]=cnt;79 }80 print(--cnt),sr[++C]=10;81 for(int i=1;i<=n;++i){82 int u=w[i];83 if(!vis[u]){84 print(u),sr[++C]=32,vis[u]=1;85 while(Pre[u]&&Pre[u]!=t>>1){86 u=Pre[u];87 vis[u]=1;88 print(u),sr[++C]=32;89 }90 sr[++C]=10;91 }92 }93 Ot();94 return 0;95 }