10.10考试总结

来源:互联网 发布:android应用程序优化 编辑:程序博客网 时间:2024/06/01 20:00

矩阵乘法

(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
【提示】
一个nt的矩阵A乘以一个tm的矩阵B,答案是一个nm的矩阵C,且满足c[i,j]=a[i,k]b[k,j],其中1<=k<=t。即,矩阵C的第i行第j列的元素等于把矩阵A的第i行于矩阵B的第j列的元素一一对应相乘后作和。注意,矩阵乘法满足结合律但是不满足交换律,即A×B不一定等于B×A。但矩阵乘法满足结合律,即ABC=A(BC)

【数据规模与约定】
对于20%的数据,n=1
对于60%的数据,n<=100
对于100%的数据,1<=n<=1000
矩阵A和矩阵B中的元素为小于1000的非负整数。
矩阵C中的元素在int范围内

要判断A×B=C,可以rand出一个1n的矩阵r,则一定有r×A×B=r×C,因为矩阵乘法满足结合律,那么就有(r×A)×B=r×C算出r×A在乘上B判断是否等于r×C就可以了
思想大概就是把两个nn的矩阵相乘转化成了1n的矩阵和nn的矩阵相乘,时间复杂度为n2

代码如下:

#include<cstdlib>#include<ctype.h>#include<cstdio>#define N 1005using 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。

注意以下题解与代码都是按1n+1来写的

定义fi表示序列中前i个数能产生的最大乘积之和,则有

fi=fi1×2+a1×ai×2+Σ2ji1jai×aj×2j1

n2算法:

因为当j1时,让j在最边上的状态一共有2j1个,则aiaj相邻的状态数一共有这么多个,产生的贡献为ai×aj×2j1
j=11在最边上的状态一共有两个,再加上a1×ai×2即可
最后再加上两个fi1(互相对称)即为当前所求的答案

把2的幂预处理出来就可以变成O(n2)的算法,60pts

代码如下:

#include<ctype.h>#include<cstdio>#define N 100050#define MOD 1000000007#define int long longusing 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)优化:

发现每个数对应的2j1是一定的,所以可以搞个前缀和记录所有应该乘的aj×2j1的和就可以了

代码如下:

#include<ctype.h>#include<cstdio>#define N 100050#define MOD 1000000007#define int long longusing 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]
就是把每个问题lr拆成1r1l1,记录下来排个序从头到尾扫一遍,放回原来的位置,颜色的记录离散化一下就可以了

注意可能有询问的颜色k不存在于原数列中,离散化后可能出问题,要开个set判断是否出现

代码如下:

#include<algorithm>#include<ctype.h>#include<cstdio>#include<set>#define N 100020using 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-5using 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;}
原创粉丝点击