Time Limits: 1000 ms
Memory Limits: 262144 KB
水叮当得到了一块五颜六色的格子形地毯作为生日礼物,更加特别的是,地毯上格子的颜色还能随着踩踏而改变。
为了讨好她的偶像虹猫,水叮当决定在地毯上跳一支轻盈的舞来卖萌~~~
地毯上的格子有N行N列,每个格子用一个0~5之间的数字代表它的颜色。
水叮当可以随意选择一个0~5之间的颜色,然后轻轻地跳动一步,地毯左上角的格子所在的联通块里的所有格子就会变成她选择的那种颜色。这里连通定义为:两个格子有公共边,并且颜色相同。
由于水叮当是施展轻功来跳舞的,为了不消耗过多的真气,她想知道最少要多少步才能把所有格子的颜色变成一样的。
每个测试点包含多组数据。
每组数据的第一行是一个整数N,表示地摊上的格子有N行N列。
接下来一个N*N的矩阵,矩阵中的每个数都在0~5之间,描述了每个格子的颜色。
N=0代表输入的结束。
对于每组数据,输出一个整数,表示最少步数。
2
0 0
0 0
3
0 1 2
1 1 2
2 2 1
0
0
3
对于30%的数据,N<=5
对于50%的数据,N<=6
对于70%的数据,N<=7
对于100%的数据,N<=8,每个测试点不多于20组数据。
Time Limits: 1000 ms
Memory Limits: 262144 KB
vani和cl2在一片树林里捉迷藏……
这片树林里有N座房子,M条有向道路,组成了一张有向无环图。
树林里的树非常茂密,足以遮挡视线,但是沿着道路望去,却是视野开阔。如果从房子A沿着路走下去能够到达B,那么在A和B里的人是能够相互望见的。
现在cl2要在这N座房子里选择K座作为藏身点,同时vani也专挑cl2作为藏身点的房子进去寻找,为了避免被vani看见,cl2要求这K个藏身点的任意两个之间都没有路径相连。
为了让vani更难找到自己,cl2想知道最多能选出多少个藏身点?
第一行两个整数N,M。
接下来M行每行两个整数x、y,表示一条从x到y的有向道路。
一个整数K,表示最多能选取的藏身点个数。
4 4
1 2
3 2
3 4
4 2
2
对于20% 的数据,N≤10,M<=20。
对于60% 的数据, N≤100,M<=1000。
对于100% 的数据,N≤200,M<=30000,1<=x,y<=N。
Time Limits: 1000 ms
Memory Limits: 262144 KB
赫克托是一个魁梧的粉刷匠,而且非常喜欢思考= =
现在,神庙里有N根排列成一直线的石柱,从1到N标号,长老要求用油漆将这些石柱重新粉刷一遍。赫克托有K桶颜色各不相同的油漆,第i桶油漆恰好可以粉刷Ci根石柱,并且,C1+C2+C3…CK=N(即粉刷N根石柱正好用完所有的油漆)。长老为了刁难赫克托,要求相邻的石柱颜色不能相同。
喜欢思考的赫克托不仅没有立刻开始粉刷,反而开始琢磨一些奇怪的问题,比如,一共有多少种粉刷的方案?
为了让赫克托尽快开始粉刷,请你尽快告诉他答案。
第一行一个正整数T,表示测试数据组数
对于每一组测试数据数据:
第1行:一个正整数K
第2行:K个正整数,表示第i桶油漆可以粉刷的石柱个数,Ci。
对于每组输入数据,输出一行一个整数,表示粉刷的方案数mod 1000000007。
3
3
1 2 3
5
2 2 2 2 2
10
1 1 2 2 3 3 4 4 5 5
10
39480
85937576
30% N≤10, T≤5
50% N≤15, T≤5
80% K≤15,Ci≤5,T≤500
100% K≤15,Ci≤6,T≤2000
今天10+55+0=65,不算好也不算太差。
先做了T2,发现可以先用floyd处理出所有可以看到的情况,然后把两两看不见的点在一个新的图中连边,这样问题就转变成了在图中找出最大完全子图。
可怜我不会这个东西,于是只好dfs了。比赛之后,才发现老王用迭代加深得了75分!
T3是统计方案的DP,我不会,弃疗,就去弄T1了。
我把连通块变成了点,相互连通的块间连边,却发现这样做并没有什么卵用……
最后暴力dfs,10分!
没想到,用迭代加深可以水多10分。
赛后
T1原来是优化暴力,由于每一次找左上角的连通块都要用很多时间,于是可以开一个标记数组,把左上角连通块标记为1,周围一圈格子标记为2,这样每次换颜色的时候在2中找相同颜色的格子,并把它相同颜色的连通块标记修改。
此外,还要加上2个剪枝:
题解还说要用迭代加深,但是不加也能过。
T2是二分图最小路径覆盖+floyd传递闭包
什么鬼?
原来floyd传递闭包就是我的那个很水的floyd,在做完这个后,如果x可以看到y,那么在二分图中连一条x到y的有向边,做一次二分图最大匹配,然后输出n-最大匹配数就可以了。
其实我不会证明
T3设 F [ i ] [ j ] F[i][j] F[i][j]表示涂到第i种颜色,有j对相邻的柱子颜色相同。
记涂到第i种颜色之后一共有S个石柱。
对于i+1这种颜色,能粉刷A次。
设把这种颜色分成k块,插进序列里面。
插进的位置中,有l个位置刚好插进在j对颜色相同的柱子中间(l<=j 且 l<=k)。
新状态的j:原有的j,新增的A-k,减少的l。
状态转移:
1 把颜色分成k块的方案数:C(A-1, k-1)
2 把块插进l个位置的方案数:C(j, l)
3 剩余块的处理方式:C(S+1-j, k-l)
转移方程如下:
F [ i + 1 ] [ j + A − k − l ] + = F [ i ] [ j ] ∗ C ( j , l ) ∗ C ( A − 1 , k − 1 ) ∗ C ( S + 1 − j , k − l ) F[i+1][j+A-k-l] += F[i][j] * C(j, l) * C(A-1, k-1) * C(S+1-j, k-l) F[i+1][j+A−k−l]+=F[i][j]∗C(j,l)∗C(A−1,k−1)∗C(S+1−j,k−l)
时间复杂度 O ( K ∗ N ∗ C ∗ C ∗ T ) O(K*N*C*C*T) O(K∗N∗C∗C∗T)
总结:比赛时要想一想怎么优化暴力和水法。
#include
using namespace std;
#define N 10
const int dx[4]={1,0,-1,0},
dy[4]={0,1,0,-1};
int a[N][N],b[N][N],n,ans,head,tail;
bool bz[N];
inline int search(int x,int y,int color)
{
int res=1,i,xx,yy;b[x][y]=1;
for(i=0;i<4;i++)
{
xx=x+dx[i],yy=y+dy[i];
if(xx&&yy&&xx<=n&&yy<=n&&b[xx][yy]!=1)
{
if(a[xx][yy]==color) res+=search(xx,yy,color);
else b[xx][yy]=2;
}
}
return res;
}
void dfs(int step,int cnt)
{
if(cnt==n*n)
{
if(ans>step) ans=step;
return;
}
int i,j,k,t;
for(i=0;i<6;i++) bz[i]=0;
for(i=1,k=0;i<=n;i++)
for(j=1;j<=n;j++)
if(b[i][j]!=1&&!bz[a[i][j]])
bz[a[i][j]]=1,k++;
if(step+k>=ans) return;
int tempa[N][N],tempb[N][N];
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
tempa[i][j]=a[i][j],tempb[i][j]=b[i][j];
for(k=0;k<6;k++)
{
for(i=1,t=0;i<=n;i++)
for(j=1;j<=n;j++)
if(b[i][j]==2&&a[i][j]==k)
t+=search(i,j,k);
if(t) dfs(step+1,cnt+t);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=tempa[i][j],b[i][j]=tempb[i][j];
}
}
int main()
{
int i,j;
while(scanf("%d",&n),n)
{
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
scanf("%d",&a[i][j]),b[i][j]=0;
b[1][1]=1;
ans=63,dfs(0,search(1,1,a[1][1]));
printf("%d\n",ans);
}
return 0;
}
#include
using namespace std;
#define S 0
#define T 500
#define N 205
struct edge
{
int end,lenth,next;
}a[100000];
bool f[N][N];
int n,m,ans,s=1,fir[T+5],dis[T+5],GAP[T+5],cur[T+5];
inline int mymin(int x,int y){return x<y?x:y;}
inline void inc(int x,int y)
{
a[++s]=(edge){y,1,fir[x]},fir[x]=cur[x]=s;
a[++s]=(edge){x,0,fir[y]},fir[y]=cur[y]=s;
}
int dfs(int k,int flow)
{
if(k==T) return flow;
int i,have=flow,temp;
for(i=cur[k];i;i=a[i].next)
if(dis[k]==dis[a[i].end]+1&&a[i].lenth)
{
cur[k]=i;
temp=dfs(a[i].end,mymin(have,a[i].lenth));
a[i].lenth-=temp,have-=temp,a[i^1].lenth+=temp;
if(!have) return flow;
}
cur[k]=fir[k];
if(!(--GAP[dis[k]])) dis[S]=T;
++GAP[++dis[k]];
return flow-have;
}
int main()
{
int i,x,y;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++) scanf("%d%d",&x,&y),f[x][y]=1;
for(i=1;i<=n;i++)
{
for(x=1;x<=n;x++) if(f[x][i])
for(y=1;y<=n;y++) if(f[i][y])
f[x][y]=1;
inc(S,i),inc(n+i,T);
}
for(x=1;x<=n;x++)
for(y=1;y<=n;y++)
if(f[x][y])
inc(x,n+y);
while(dis[S]<T) ans+=dfs(S,0x7fffffff);
printf("%d\n",n-ans);
return 0;
}
#include
#include
using namespace std;
#define mod 1000000007
int f[20][100],c[100][100],a[20];
int main()
{
int t,n,i,j,k,l,sum;
scanf("%d",&t),c[0][0]=1;
for(i=1;c[i][0]=1,i<100;i++)
for(j=1;j<=i;j++)
c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
while(t--)
{
scanf("%d",&n);
for(i=1;i<=n;i++) scanf("%d",a+i);
memset(f,0,sizeof(f));
f[1][a[1]-1]=1,sum=0;
for(i=1;sum+=a[i],i<n;i++)
for(j=0;j<sum;j++) if(f[i][j])
for(k=1;k<=a[i+1];k++)
for(l=0;l<=j&&l<=k;l++)
f[i+1][j+a[i+1]-k-l]=(f[i+1][j+a[i+1]-k-l]+1LL*f[i][j]*c[a[i+1]-1][k-1]%mod*c[j][l]%mod*c[sum+1-j][k-l]%mod)%mod;
printf("%d\n",f[n][0]);
}
return 0;
}