%%%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 #include<iostream> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cstring> 6 #include<queue> 7 #include<cmath> 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 num 19 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<int> 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 }