矩阵乘法
(matrixf.cpp,1s,256MB)
【问题描述】
给定三个n*n的矩阵A,B,C,判断C是否等于A×B。
【输入格式】
输入文件包含多组数据。第一行是一个整数T(T<=5)表示测试点个数。
对于每组数据,第一行是一个正整数n,表示矩阵大小。
接下来3*n行,每行n个整数,分别表示A、B和C。
【输出格式】
对于每组数据,如果C=A×B,输出”Yes”,否则输出”No”。
【样例输入】
2
1
2
3
5
2
2 3
3 5
0 1
1 1
3 5
5 8
【样例输出】
No
Yes
【提示】
一个
n∗t
的矩阵A乘以一个
t∗m
的矩阵B,答案是一个
n∗m
的矩阵C,且满足
c[i,j]=∑a[i,k]∗b[k,j]
,其中1<=k<=t。即,矩阵C的第i行第j列的元素等于把矩阵A的第i行于矩阵B的第j列的元素一一对应相乘后作和。注意,矩阵乘法满足结合律但是不满足交换律,即A×B不一定等于B×A。但矩阵乘法满足结合律,即
A∗B∗C=A∗(B∗C)
。
【数据规模与约定】
对于20%的数据,n=1
对于60%的数据,n<=100
对于100%的数据,1<=n<=1000
矩阵A和矩阵B中的元素为小于1000的非负整数。
矩阵C中的元素在int范围内
要判断
A×B=C
,可以rand出一个
1∗n
的矩阵r,则一定有
r×A×B=r×C
,因为矩阵乘法满足结合律,那么就有
(r×A)×B=r×C
算出
r×A
在乘上
B
判断是否等于
思想大概就是把两个
n∗n
的矩阵相乘转化成了
1∗n
的矩阵和
n∗n
的矩阵相乘,时间复杂度为
n2
代码如下:
#include<cstdlib>
#include<ctype.h>
#include<cstdio>
#define N 1005
using namespace std;
inline int read(){
int x=0,f=1;char c;
do {c=getchar();if(c=='-') f=-1;}while(!isdigit(c));
do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));
return x*f;
}
inline int min(int a,int b){return a<b?a:b;}
int T,n;
int r[N],d1[N],d2[N],d3[N];
struct Matrix{
int a[N][N];
inline void read_Matrix(int k){
for(int i=1;i<=k;i++)
for(int j=1;j<=k;j++)
a[i][j]=read();
}
}a,b,c;
inline void mul(int a[],int b[N][N],int c[]){
for(int i=1;i<=n;i++){
c[i]=0;
for(int j=1;j<=n;j++)
c[i]+=a[j]*b[j][i];
}
}
inline bool check(){
mul(r,a.a,d1);
mul(d1,b.a,d2);
mul(r,c.a,d3);
for(int i=1;i<=n;i++)
if(d3[i]!=d2[i]) return false;
return true;
}
main(){
srand(19260817);
for(int i=1;i<=1000;i++) r[i]=rand();//随机矩阵
T=read();
while(T--){
n=read();
a.read_Matrix(n);b.read_Matrix(n);c.read_Matrix(n);
if(check()) puts("Yes");
else puts("No");
}
return 0;
}
数字游戏
(num.cpp, 1s,256MB)
问题描述
有n+1个数,分别为a0,a1,a2,…,an。小K正在用这n+1个数玩游戏,首先小K会把数字a0放中间,第i次操作他会将ai放在左端或者右端。我们知道小K有2n种方法摆放这些数字。
之后小K会对这2n种方法摆放方法求一个评估值,一种摆放方法的评估值为所有相邻两数的乘积之和。
小K想知道这2n种方法摆评估值之和为多少,由于答案太大,你只需要告诉他模109+7的结果。
输入格式
第一行一个正整数n。
接下来一行有n+1个正整数,分别表示a0,a1,a2,…,an。
输出格式
一行一个正整数,表示答案。
输入样例
2
1 2 1
输出样例
14
数据范围
对于30%的数据 ,1<=n<=10。
对于60%的数据 ,1<=n<=1000。
对于100%的数据 ,1<=n<=100000,ai<=109。
注意以下题解与代码都是按 1→n+1 来写的
定义
fi
表示序列中前
i
个数能产生的最大乘积之和,则有
n2 算法:
因为当
j≠1
时,让
j
在最边上的状态一共有
当
j=1
时
1
在最边上的状态一共有两个,再加上
最后再加上两个
fi−1
(互相对称)即为当前所求的答案
把2的幂预处理出来就可以变成 O(n2) 的算法,60pts
代码如下:
#include<ctype.h>
#include<cstdio>
#define N 100050
#define MOD 1000000007
#define int long long
using namespace std;
typedef long long ll;
inline int read(){
int x;
scanf("%lld",&x);
return x;
}
int n;
int a[N];
ll f[N];
inline int quick_pow(ll x,ll k){
ll sum=1;
while(k){
if(k&1) sum=sum*x%MOD;
x=x*x%MOD;
k>>=1;
}
return sum;
}
inline void solve(){
for(int i=2;i<=n;i++){
for(int j=2;j<i;j++){
f[i]=(f[i]+a[i]*a[j]*quick_pow(2,j-1)%MOD)%MOD;
}
f[i]=(f[i]+a[i]*a[1]*2%MOD)%MOD;
f[i]=(f[i]+f[i-1]*2%MOD)%MOD;
}
printf("%lld\n",f[n]);
}
main(){
n=read()+1;
for(int i=1;i<=n;i++) a[i]=read();
solve();
return 0;
}
O(n)优化:
发现每个数对应的 2j−1 是一定的,所以可以搞个前缀和记录所有应该乘的 aj×2j−1 的和就可以了
代码如下:
#include<ctype.h>
#include<cstdio>
#define N 100050
#define MOD 1000000007
#define int long long
using namespace std;
typedef long long ll;
inline int read(){
int x=0,f=1;char c;
do {c=getchar();if(c=='-') f=-1;}while(!isdigit(c));
do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));
return x*f;
}
int n;
int a[N];
ll f[N],q[N];
inline int quick_pow(int x,int k){
int sum=1;
while(k){
if(k&1) sum=sum*x%MOD;
x=x*x%MOD;
k>>=1;
}
return sum;
}
inline void solve(){
for(int i=2;i<=n;i++){
q[i]=(q[i-1]+a[i]*quick_pow(2,i-1))%MOD;//2的幂可以预处理出来
f[i]=(f[i]+a[i]*q[i-1]%MOD)%MOD;
f[i]=(f[i]+a[i]*a[1]*2%MOD)%MOD;
f[i]=(f[i]+f[i-1]*2%MOD)%MOD;
}
printf("%lld\n",f[n]);
}
main(){
n=read()+1;
for(int i=1;i<=n;i++) a[i]=read();
solve();
return 0;
}
物以类聚
(kind.cpp,1s,256MB)
【问题描述】
吉林省OIER们都喜欢吃糖,所以冬令营组委会在地上摆了n个各种各样的糖,标号为1……n,OIER们特别想知道在标号L到标号R之间共有种类为k的糖有多少块。
【输入格式】
从文件kind.in中输入数据。
第 1 行:两个空格隔开的正整数 n 和 m
第 2 行:n 个空格隔开的整数,第 i 个整数为第 i 个糖果的种类
接下来 m 行,每行三个整数 L,R,k 描述一个询问
【输出格式】
输出到文件kind.out中。
m 行每行一个整数对应每个询问的答案。
【样例输入】
5 3
1 2 3 2 3
1 3 1
2 4 2
3 4 3
【样例输出】
1
2
1
【数据规模与约定】
对于 50%的数据, n,m<=2000
对于 100%的数据, n,m<=100000,k在int范围内。
简单的离线处理,方法类似于BZOJ[3626]
就是把每个问题
l→r
拆成
1→r
减
1→l−1
,记录下来排个序从头到尾扫一遍,放回原来的位置,颜色的记录离散化一下就可以了
注意可能有询问的颜色k不存在于原数列中,离散化后可能出问题,要开个set判断是否出现
代码如下:
#include<algorithm>
#include<ctype.h>
#include<cstdio>
#include<set>
#define N 100020
using namespace std;
inline int read(){
int x=0,f=1;char c;
do {c=getchar();if(c=='-') f=-1;}while(!isdigit(c));
do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));
return x*f;
}
set<int>s;
set<int>::iterator it;
int n,m,nn,l,r,k,top;
int a[N],num[N],b[N],ans[N][3],c[N];
struct Query{
int x,k,belong,num;
Query(int _x=0,int _k=0,int _belong=0,int _num=0):x(_x),k(_k),belong(_belong),num(_num){}
}q[N<<1];
inline bool cmp(Query a,Query b){return a.x<b.x;}
main(){
n=read();m=read();
for(int i=1;i<=n;i++) c[i]=b[i]=a[i]=read();
sort(b+1,b+n+1);
sort(c+1,c+n+1);
nn=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++){
s.insert(a[i]);
a[i]=lower_bound(b+1,b+nn+1,a[i])-b;
}
for(int i=1;i<=m;i++){
l=read();r=read();k=read();
it=s.lower_bound(k);
if(*it!=k) continue;//判断是否合法
k=lower_bound(b+1,b+nn+1,k)-b;
q[++top]=Query(l-1,k,i,1);
q[++top]=Query(r,k,i,2);
}
sort(q+1,q+top+1,cmp);
int pre=1;
for(int i=0;i<=n;i++){
num[a[i]]++;
while(q[pre].x==i){
ans[q[pre].belong][q[pre].num]=num[q[pre].k];
pre++;
}
}
for(int i=1;i<=m;i++){
printf("%d\n",ans[i][2]-ans[i][1]);
}
return 0;
}
4、矩阵
(matrix.cpp,1s ,256MB)
问题描述
定义矩阵A= 的行列式为det(A)=ad-bc。
我们称行列式为0的矩阵为奇异矩阵。
现在给出一个矩阵A,要求一个奇异矩阵B,使得A-B中的元素的中绝对值最大值最小。
输入格式
第一行两个整数a,b
第二行两个整数c,d
输出格式
输出矩阵A-B中的绝对值最大的元素的绝对值最小。
只要答案与标准答案不成果10-3即可,输出的小数位数不要超过15位。
输入样例
1 2
3 4
输出样例
0.200000000000
样例解释
数据范围
对于100%的数据,|a|,|b|,|c|,|d|<=109
题解:
这个为什么是对的yy一下就好了吧..
代码如下:
#include<algorithm>
#include<cstdlib>
#include<ctype.h>
#include<cstdio>
#define eps 1e-5
using namespace std;
inline int read(){
int x=0,f=1;char c;
do {c=getchar();if(c=='-') f=-1;}while(!isdigit(c));
do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));
return x*f;
}
double l,r,mid,minad,maxad,maxbc,minbc,ans,a,b,c,d;
main(){
a=read();b=read();c=read();d=read();
l=0;r=1000000000ll;
while(l<=r){
mid=(l+r)/2;
maxad=max((a+mid)*(d+mid),max((a-mid)*(d-mid),max((a-mid)*(d+mid),(a+mid)*(d-mid))));
minad=min((a+mid)*(d+mid),min((a-mid)*(d-mid),min((a-mid)*(d+mid),(a+mid)*(d-mid))));
maxbc=max((b+mid)*(c+mid),max((b-mid)*(c-mid),max((b-mid)*(c+mid),(b+mid)*(c-mid))));
minbc=min((b+mid)*(c+mid),min((b-mid)*(c-mid),min((b-mid)*(c+mid),(b+mid)*(c-mid))));
if((maxbc>=minad&&minbc<=minad)||(minad<=minbc&&maxad>=minbc)) ans=mid,r=mid-eps;
else l=mid+eps;
}
printf("%.8lf",ans);
return 0;
}