bzoj3583 杰杰的女性朋友 || bzoj4362 Graph
http://210.33.19.103/problem/2174
很显然是矩阵快速幂的题,设有in和ou矩阵,设in矩阵的转置为in'
显然可以直接暴力求出任意两点间走一步路径条数,然后求其d次幂,但是这样子复杂度不对
注意到设任意两点间走一步路径条数的矩阵为A,那么A=ou*in',A^d=(ou*in')^d=ou*(in'*ou)^(d-1)*in'(当然d==1时直接特判掉)
in'*ou就是一个K*K的矩阵了,复杂度很对的样子
好像还有点不对。。。题意要求的是前缀和,问题也不大,
设P=in'*ou
题目要求的是ou*P^0*in'+ou*P^1*in'+..+ou*P^(d-1)*in'=ou*(P^0+P^1+..+P^(d-1))*in'
这个P^0+P^1+..+P^(d-1),搞一个矩阵套矩阵可以算(的确是可以用的23333)
搞两个矩阵X,Y,X=(I,I),Y是一个2*2的矩阵,第一行为(P,P),第二行为(0,I)(I表示K阶单位矩阵,0表示K阶零矩阵)
那么求Z=X*Y^(d-1),Z的第一行第二列的值即为P^0+P^1+..+P^(d-1)
(以上与求值的前缀和的方法是一样的)
明明是思路很清晰的题啊,然而我又是一天被续掉了。。。
鬼畜卡常题啊。。。
此题最好,最正确的方法是不用任何结构体,手写所有矩阵相乘
绝对不能用vector来存不同大小的矩阵!不然会T飞
绝对不要尝试在这类地方用模板类来实现嵌套矩阵!搞不出来的
嵌套矩阵很难写,常数又大,后来我干脆把这个嵌套的矩阵拆开(2*2的矩阵,其中每个元素是K*K的矩阵,就拆成(2*K)*(2*K)的矩阵),目前可以确认是对的
O3卡过代码:
#pragma GCC optimize(3)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cassert>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
//#define assert(x)
const int md=;
struct M_NN
{
int d[][];int x,y;
void resize(int a,int b)
{
x=a;y=b;
memset(d,,sizeof(d));
//d.clear();
//d.resize(x+1);
//for(int i=1;i<=x;i++) d[i].resize(y+1);
}
};
struct M_NK
{
int d[][];int x,y;
void resize(int a,int b)
{
x=a;y=b;
memset(d,,sizeof(d));
//d.clear();
//d.resize(x+1);
//for(int i=1;i<=x;i++) d[i].resize(y+1);
}
};
struct M_KN
{
int d[][];int x,y;
void resize(int a,int b)
{
x=a;y=b;
memset(d,,sizeof(d));
//d.clear();
//d.resize(x+1);
//for(int i=1;i<=x;i++) d[i].resize(y+1);
}
};
struct M_KK
{
int d[][];int x,y;
void resize(int a,int b)
{
x=a;y=b;
memset(d,,sizeof(d));
//d.clear();
//d.resize(x+1);
//for(int i=1;i<=x;i++) d[i].resize(y+1);
}
};
/*
void init_0(M &p)
{
p.resize(p.x,p.y);
}
*/
M_NK operator*(const M_NK &a,const M_KK &b)
{
assert(a.y==b.x);
M_NK c;c.resize(a.x,b.y);
int i,j,k;
for(i=;i<=a.x;i++)
for(j=;j<=b.x;j++)
for(k=;k<=b.y;k++)
c.d[i][k]=(c.d[i][k]+ll(a.d[i][j])*b.d[j][k]%md)%md;
return c;
} M_NN operator*(const M_NK &a,const M_KN &b)
{
assert(a.y==b.x);
M_NN c;c.resize(a.x,b.y);
int i,j,k;
for(i=;i<=a.x;i++)
for(j=;j<=b.x;j++)
for(k=;k<=b.y;k++)
c.d[i][k]=(c.d[i][k]+ll(a.d[i][j])*b.d[j][k]%md)%md;
return c;
}
M_KK operator*(const M_KN &a,const M_NK &b)
{
assert(a.y==b.x);
M_KK c;c.resize(a.x,b.y);
int i,j,k;
for(i=;i<=a.x;i++)
for(j=;j<=b.x;j++)
for(k=;k<=b.y;k++)
c.d[i][k]=(c.d[i][k]+ll(a.d[i][j])*b.d[j][k]%md)%md;
return c;
}
M_KK operator*(const M_KK &a,const M_KK &b)
{
assert(a.y==b.x);
M_KK c;c.resize(a.x,b.y);
int i,j,k;
for(i=;i<=a.x;i++)
for(j=;j<=b.x;j++)
for(k=;k<=b.y;k++)
c.d[i][k]=(c.d[i][k]+ll(a.d[i][j])*b.d[j][k]%md)%md;
return c;
}
M_KK o,tt2,t1,t2;
M_NK ou1;M_KN in1;
M_KK p;
int in[][],ou[][];
M_KK poww(const M_KK &a,int b)
{
M_KK ans=o,base=a;
assert(a.x==a.y);
for(;b;base=base*base,b>>=)
if(b&)
ans=ans*base;
return ans;
} int n,K,m;
int solve(int u,int v,int d)
{
if(d==) return u==v;
M_KK tt=t1*poww(t2,d-);
int i,j;
for(i=;i<=K;i++)
{
for(j=;j<=K;j++)
{
tt2.d[i][j]=tt.d[i][j+K];
}
}
M_NK t2=ou1*tt2;int an=u==v;
for(i=;i<=t2.y;i++)
an=(an+ll(t2.d[u][i])*in1.d[i][v]%md)%md;
return an;
}
int main()
{
//freopen("/tmp/3583/6.in","r",stdin);
//freopen("/tmp/3583/6.ans","w",stdout);
int i,j,u,v,d;
scanf("%d%d",&n,&K);
for(i=;i<=n;i++)
{
for(j=;j<=K;j++)
{
scanf("%d",&ou[i][j]);
}
for(j=;j<=K;j++)
{
scanf("%d",&in[i][j]);
}
}
ou1.resize(n,K);
for(i=;i<=n;i++)
{
for(j=;j<=K;j++)
{
ou1.d[i][j]=ou[i][j];
}
}
in1.resize(K,n);
for(i=;i<=K;i++)
{
for(j=;j<=n;j++)
{
in1.d[i][j]=in[j][i];
}
}
p=in1*ou1;
t1.resize(K,*K);
for(i=;i<=K;i++) t1.d[i][i]=t1.d[i][i+K]=;
t2.resize(*K,*K);
for(i=;i<=K;i++)
{
for(j=;j<=K;j++)
{
t2.d[i][j]=t2.d[i][j+K]=p.d[i][j];
}
}
for(i=;i<=K;i++) t2.d[i+K][i+K]=;
tt2.resize(K,K);
o.resize(*K,*K);
for(i=;i<=*K;i++) o.d[i][i]=;
scanf("%d",&m);
while(m--)
{
scanf("%d%d%d",&u,&v,&d);
printf("%d\n",solve(u,v,d));
//return 0;
}
return ;
}
一份有分,可以跑的代码:
#pragma GCC optimize(3)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
//#include<cassert>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
#define vector myvec
template<typename T>
struct myvec
{
T *p;int sz;
myvec():p(),sz(){}
~myvec(){delete[] p;}
myvec &operator=(const myvec &b)
{
delete[] p;
sz=b.sz;
p=new T[sz];
for(T *i1=p,*i2=b.p;i1!=p+sz;++i1,++i2) *i1=*i2;
return *this;
}
myvec(const myvec &b):p(),sz(){*this=b;}
void resize(int d){sz=d;delete[] p;p=new T[d]();}
T &operator[](int d){return p[d];}
const T &operator[](int d)const{return p[d];}
};
const ll md=;
struct M1
{
vector<vector<ll> > d;int x,y;
M1();
void resize(int xx,int yy)
{
x=xx;y=yy;
d.resize(x+);
for(int i=;i<=x;i++) d[i].resize(y+);
}
};
struct M2
{
M1 d[][];int x,y;
M2();
void resize_sub(int xx,int yy)
{
int i,j;
for(i=;i<=x;i++)
for(j=;j<=y;j++)
d[i][j].resize(xx,yy);
}
};
void init_0(M1 &p)
{
//p.d.clear();
p.resize(p.x,p.y);
}
void init_0(M2 &p)
{
int i,j;
for(i=;i<=;i++)
for(j=;j<=;j++)
init_0(p.d[i][j]);
}
void init_1(M1 &p)
{
init_0(p);//assert(p.x==p.y);
for(int i=;i<=p.x;i++) p.d[i][i]=;
}
void init_1(M2 &p)
{
init_0(p);//assert(p.x==p.y);
for(int i=;i<=p.x;i++) init_1(p.d[i][i]);
}
M1::M1(){x=y=;init_0(*this);}
M2::M2(){x=y=;init_0(*this);}
M1 operator+(const M1 &a,const M1 &b)
{
//assert(a.x==b.x&&a.y==b.y);
M1 c;c.resize(a.x,a.y);
int i,j;
for(i=;i<=a.x;i++)
for(j=;j<=a.y;j++)
c.d[i][j]=(a.d[i][j]+b.d[i][j])%md;
return c;
}
M1 operator*(const M1 &a,const M1 &b)
{
//assert(a.y==b.x);
M1 c;c.resize(a.x,b.y);
int i,j,k;
for(i=;i<=a.x;i++)
for(j=;j<=b.x;j++)
for(k=;k<=b.y;k++)
c.d[i][k]=(c.d[i][k]+a.d[i][j]*b.d[j][k])%md;
return c;
}
M2 operator*(const M2 &a,const M2 &b)
{
//assert(a.y==b.x);
M2 c;c.x=a.x;c.y=b.y;c.resize_sub(a.d[][].x,a.d[][].y);
int i,j,k;
for(i=;i<=a.x;i++)
for(j=;j<=b.x;j++)
for(k=;k<=b.y;k++)
c.d[i][k]=(c.d[i][k]+a.d[i][j]*b.d[j][k]);
return c;
}
M1 ou1,in1,p;
int ou[][],in[][];
M2 poww(const M2 &a,ll b)
{
//printf("tt%d %d\n",a.x,a.y);
M2 ans,base=a;/*assert(a.x==a.y);*/ans.x=ans.y=a.x;
ans.resize_sub(a.d[][].x,a.d[][].y);init_1(ans);
for(;b;base=base*base,b>>=)
if(b&)
ans=ans*base;
return ans;
}
int n,K,m; /*
void out(const M1 &a)
{
puts("start");
int i,j;
for(i=1;i<=a.x;i++)
{
for(j=1;j<=a.y;j++)
{
printf("%lld ",a.d[i][j]);
}
puts("");
}
puts("end");
fflush(stdout);
} void out(const M2 &p)
{
puts("st");
printf("xy%d %d\n",p.x,p.y);
for(int i=1;i<=p.x;i++)
for(int j=1;j<=p.y;j++)
out(p.d[i][j]),puts("");
puts("ed");
}
*/
M2 t1,t2;
int solve(int u,int v,int d)
{
if(d==) return u==v;
return ((u==v)+(ou1*((t1*poww(t2,d-)).d[][])*in1).d[u][v])%md;
}
int main()
{
int i,j,u,v,d;
scanf("%d%d",&n,&K);
for(i=;i<=n;i++)
{
for(j=;j<=K;j++)
{
scanf("%d",&ou[i][j]);
}
for(j=;j<=K;j++)
{
scanf("%d",&in[i][j]);
}
}
ou1.resize(n,K);
for(i=;i<=n;i++)
{
for(j=;j<=K;j++)
{
ou1.d[i][j]=ou[i][j];
}
}
in1.resize(K,n);
for(i=;i<=K;i++)
{
for(j=;j<=n;j++)
{
in1.d[i][j]=in[j][i];
}
}
p=in1*ou1;
t1.x=;t1.y=;t1.resize_sub(K,K);
//t1.d[1][1]=M1(1,K,K);
init_1(t1.d[][]);init_1(t1.d[][]);
t2.x=t2.y=;t2.resize_sub(K,K);
t2.d[][]=t2.d[][]=p;
//t2.d[2][2]=M1(1,K,K);
init_1(t2.d[][]);
//out((t1*poww(t2,0)).d[1][2]);
scanf("%d",&m);
while(m--)
{
scanf("%d%d%d",&u,&v,&d);
printf("%d\n",solve(u,v,d));
}
return ;
}
bzoj3583 杰杰的女性朋友 || bzoj4362 Graph的更多相关文章
- bzoj3583: 杰杰的女性朋友 && 4362: Graph
Description 给出一张n个点的有向图G(V,E).对于任意两个点u,v(u可以等于v),u向v的连边数为: ∑OUT(u,i) * IN(v,i),其中1<=i<=K 其中k和数 ...
- [BZOJ3583]杰杰的女性朋友(矩阵快速幂)
杰杰的女性朋友 时间限制:10s 空间限制:256MB 题目描述 杰杰是魔法界的一名传奇人物.他对魔法具有深刻的洞察力,惊人的领悟力,以及令人叹为观止的创造力.自从他从事魔法竞赛以来,短短几 ...
- BZOJ3583 杰杰的女性朋友 矩阵
原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ3583.html 题目传送门 - BZOJ3583 题意 有一个 $n$ 个点构成的有向图. 对于每一个 ...
- BZOJ3583 : 杰杰的女性朋友
将$I$转置,设$G=OI$,则$ans=G^0+G^1+...+G^d$. 注意到$G^d=O(IO)^{d-1}I$,而$IO$是大小为$k\times k$的矩阵,可以通过倍增在$O(k^3\l ...
- 复旦大学EWP菁英女性课程(复旦卓越女性课程改版后第一期) _复旦大学、女性课程、高级研修班、心理学、EWP_培训通课程
复旦大学EWP菁英女性课程(复旦卓越女性课程改版后第一期) _复旦大学.女性课程.高级研修班.心理学.EWP_培训通课程 复旦大学EWP菁英女性课程(复旦卓越女性课程改版后第一期) 学 ...
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
- cojs QAQ的矩阵 题解报告
题目描述非常的清晰 首先我们考虑(A*B)^m的求法,这个部分可以参考BZOJ 杰杰的女性朋友 我们不难发现(A*B)^m=A*(B*A)^(m-1)*B A*B是n*n的矩阵,而B*A是k*k的矩阵 ...
- qbxt五一数学Day1
目录 I. 基础知识 1. 带余除法(小学) 1. 定义 2. 性质 2. 最大公约数(gcd)/ 最小公倍数(lcm) 1. 定义 2. 性质 3. 高精度 II. 矩阵及其应用 1. 定义 2. ...
- DOM实战
作者声明:本博客中所写的文章,都是博主自学过程的笔记,参考了很多的学习资料,学习资料和笔记会注明出处,所有的内容都以交流学习为主.有不正确的地方,欢迎批评指正 视频来源:https://www.bil ...
随机推荐
- nginx启动不了
nginx简介 Nginx是一个高性能的HTTP和反向代理服务器. 支持的操作系统众多,windows.linux. MacOS X: 可实现负载均衡: Rewrite功能强大: 电商架构大部分都采用 ...
- buntu下命令行安装jdk,android-studio,及genymotion虚拟机来进行android开发【转】
本文转载自:http://www.cnblogs.com/iamhenanese/p/5491862.html 安装JDK 从oracle官网下最新版的linux64位的jdk包(现在最新为jdk-8 ...
- HDU 5969 最大的位或 —— 贪心 + 二进制的理解
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5969 最大的位或 Time Limit: 2000/1000 MS (Java/Others) ...
- Java线程池技术以及实现
对于服务端而言,经常面对的是客户端传入的短小任务,需要服务端快速处理并返回结果.如果服务端每次接受一个客户端请求都创建一个线程然后处理请求返回数据,这在请求客户端数量少的阶段看起来是一个不错的选择,但 ...
- Java聊天室[长轮询]
今天看到有人分享java实现的聊天室,想起很久以前还在热衷于java的时候也做过一个web聊天室,不拿出来晒晒,可能再也不为人知了,单纯是一个兴趣作品,稳定性不好,也没有考虑连接数和并发的问题,拿出来 ...
- adb 读写模式 挂载文件系统
删除需要把system挂载为读写,用到了这篇文章的这个命令: shell@android:/ # mount -o rw,remount yassf2 /system/ 完整文章转自:http:/ ...
- luogu 3812 【模板】 线性基
线性基是一个支持在集合里插入数并查询最大子集异或值 #include<iostream> #include<cstdio> #include<cstring> #i ...
- distutils 打包setup.py
from distutils.core import setup setup(name='hello', version='1.0', description='test example', auth ...
- javascript之闭包,递归,深拷贝
闭包 理解:a函数执行后return出b函数且b函数可以访问a函数的数据 好处:子函数存储在复函数内部,子函数执行完不会被自动销毁 坏处:占用内存比较大 ex: function bibao(){ v ...
- Tomcat 安装之后,双击Tomcat.exe,无法运行成功,怎么办?
Log形式多种多样,有的时候跟下面一样: 首先的解决方案就是:修改server.xml中所有的端口,因为不只8080端口可能被占用! 我在出问题的时候就修改8080端口.结果死活运行不了,纠结一些时间 ...