bzoj 2165: 大楼【Floyd+矩阵乘法+倍增+贪心】
1<<i的结果需要是long long的话i是long long是没用的……要写成1ll<<i……我别是个傻子吧
虽然写的是二进制贪心,但是我觉得二分可能更好写吧(但是会慢)
首先把矩阵乘法转换成Floyd的形式,注意是进行一次更新,也就是另开一个数组使得更新之后每个[i][j]都变成经过一或两段路,(i,j)之间的最长路
然后就可以倍增了,一直相乘就会变成经过一二四六八…段路,(i,j)之间的最长路,这里把倍增过程记下来
直到某次相乘之后符合要求(也就是[1][x]的最长路大于等于m)
然后按照二进制位从大到小贪心,扫倍增过程能乘就乘,然后再答案上加上1ll<<i
最后答案要+1
#include<iostream>
#include<cstdio>
using namespace std;
const int N=105;
const long long inf=1e18;
long long T,n,m;
struct qwe
{
long long a[N][N];
qwe operator * (const qwe &b) const
{
qwe c;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
c.a[i][j]=-inf;
for(int i=1;i<=n;i++)
c.a[i][i]=0;
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
c.a[i][j]=max(c.a[i][j],a[i][k]+b.a[k][j]);
return c;
}
}f[N];
long long read()
{
long long r=0,f=1;
char p=getchar();
while(p>'9'||p<'0')
{
if(p=='-')
f=1;
p=getchar();
}
while(p>='0'&&p<='9')
{
r=r*10+p-48;
p=getchar();
}
return r*f;
}
bool ok(qwe a)
{
for(int i=1;i<=n;i++)
if(a.a[1][i]>=m)
return 1;
return 0;
}
int main()
{
T=read();
while(T--)
{
n=read(),m=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
f[0].a[i][j]=read();
if(f[0].a[i][j]==0)
f[0].a[i][j]=-inf;
}
long long cnt=0,ans=1;
while(1)
{
f[cnt+1]=f[cnt]*f[cnt];
if(ok(f[++cnt]))
break;
}
qwe p=f[0];
for(int i=cnt;i>=0;i--)
{
qwe nw=p*f[i];
if(!ok(nw))
{
ans+=1ll<<i;
p=nw;
}
}
printf("%lld\n",ans+1);
}
return 0;
}