题目大意就是每个人都有自己喜欢的座位编号,喜欢的编号是要x的倍数就好,(1<=x<=10)一共10种情况,每种情况的人的数目不一样。
给你一个n,代表有编号1-n这n个座位,问最多能满足多少人的喜爱要求。
lcm(1...10)=2520 x跟k*lcm+x的因子情况是一样的(对于1-10这十个数来说) 因为显然k*lcm可以提出x的任意因子,而若不是x的因子,后面+x提一下会出现小数显然就不满足情况了 ,所以是完全一样的。。那么只要预处理出来1-2520的因子情况就可以了。。
然后就随便跑跑网络流就可以了。。。。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=111; int q[N],head[N],tot,S,T,dis[N]; struct node{ int to,next,w; }e[N<<4]; void add(int u,int v,int w){ e[tot].to=v;e[tot].next=head[u];e[tot].w=w;head[u]=tot++; e[tot].to=u;e[tot].next=head[v];e[tot].w=0;head[v]=tot++; } bool bfs(){ int l=0,r=0; q[r++]=S; memset(dis,-1,sizeof(dis)); dis[S]=0; while(l<r) { int u=q[l++]; for(int i=head[u];~i;i=e[i].next){ int v=e[i].to; if(dis[v]==-1&&e[i].w>0) { dis[v]=dis[u]+1; q[r++]=v; if(v==T) return true; } } } return false; } int dfs(int s,int low){ if(!low||s==T) return low; int ans=low,a; for(int i=head[s];~i;i=e[i].next){ int v=e[i].to; if(e[i].w>0&&dis[v]==dis[s]+1&&(a=dfs(v,min(ans,e[i].w)))) { ans-=a; e[i].w-=a; e[i^1].w+=a; if(!ans) return low; } } if(low==ans) dis[s]=-1; return low-ans; } int vis[1<<11],mark[2800],lim[88],p[88]; void init(){ int cont=0; for(int i=0;i<2520;++i) { int S=0; for(int j=1;j<=10;++j) if(i%j==0) S|=1<<j; if(!vis[S]) vis[S]=++cont,p[cont]=S; mark[i]=vis[S]; } } int main(){ init(); int Ta,n,x; for(scanf("%d",&Ta);Ta--;){ tot=0; memset(head,-1,sizeof(head)); memset(lim,0,sizeof(lim)); scanf("%d",&n); S=0,T=59; for(int i=0;i<2520;++i) { int now=n/2520; if(i&&n%2520>=i) ++now; lim[mark[i]]+=now; } for(int i=1;i<=48;++i) add(i+10,T,lim[i]); for(int i=1;i<=10;++i) { scanf("%d",&x); if(x) { add(S,i,x); for(int j=1;j<=48;++j) if(p[j]&(1<<i)) add(i,j+10,x); } } int ans=0; while(bfs()) ans+=dfs(S,1e9+7); printf("%d\n",ans); } }