10月集训test10

来源:互联网 发布:linux cp 带目录结构 编辑:程序博客网 时间:2024/05/31 18:31

又是写考试总结的时候了。。。。
这次考试60+10+55=125.
第一题真心是没有找到更优的方法,后面丢的分全是因为超时;第二题并没有想到动规,所以华丽丽拿了特判的分;第三题。。大概是暴力写炸了吧(不过其实暴力就可以直接过正解了)。
天凉了,让死去的脑细胞埋得更深一点吧。

1.刮刮卡

问题描述

企鹅豆豆在和一个良心商贩玩刮刮卡。
一张刮刮卡价值为A元,刮开可以获得B元现金和B个积分。由于商贩特别良心,所以他告诉了豆豆每张刮刮卡的A和B值,并且允许豆豆先拿到B元现金再支付A元费用。他同时保证,所有刮刮卡得到的钱等于购买所有刮刮卡花费的钱。现在他把刮刮卡排成一列,放在豆豆面前。
地主家的傻儿子豆豆有顺着买的强迫症,所以他会先把序列最前面K张刮刮卡顺次移到最后面,然后开始顺着一张一张得和商贩交易。豆豆一开始不亏不赚,如果某个时刻某张卡片交易结束之后,他有亏损的话就会结束这个交易。
豆豆并不在意自己能赚多少,反而他对积分很感兴趣。他想知道K取多少他才能尽可能多地得到积分。

输入格式

第一行一个整数N代表总刮刮卡个数。
接下来一行N个数,表示第i张刮刮卡的Bi值。
接下来一行N个数,表示第i张刮刮卡的Ai值。

输出格式

输出一个整数K,如果得到的积分相同,输出最小的K。

输入样例

5
4 6 2 8 4
1 5 7 9 2

输出样例

4

样例说明

如果一张都不挪动(K=0),豆豆最终会得到12积分。
如果把前四张放到最后(4 4 6 2 8),豆豆最终可以得到24积分。

数据范围

对于30%的数据,N≤1000。
对于100%的数据,N≤1000000,0≤Ai,Bi≤1000。

不得不说,被加粗了的那句话是很重要的一句,这标志着总有一种排列使得最终的积分为Ai或是Bi的和。这是先以任意卡片为起点,算出所有卡片的前缀和,则前缀和最小的卡片应为起始卡片,再算出若以它为起点该移动多少张牌即可。

#include<iostream>#include<cstdlib>#include<cstdio>#include<cstring>#include<string>#include<ctime>#include<cmath>#include<algorithm>#include<cctype>#include<iomanip>using namespace std;int n,x;bool f[1000010];int a[1000010],b[1000010];inline int read(){    int i=0;    char c;    for(c=getchar();c<'0'||c>'9';c=getchar());    for(;c>='0'&&c<='9';c=getchar())        i=(i<<1)+(i<<3)+c-'0';    return i;}int main(){    //freopen("rock.in","r",stdin);    //freopen("rock.out","w",stdout);    n=read();    for(int i=1;i<=n;i++)        b[i]=read();    for(int i=1;i<=n;i++)       {        x=read();        a[i]=b[i]-x;    }       for(int i=1;i<=n;i++)        a[i]+=a[i-1];    int mn=1e9,pos=-1;    for(int i=0;i<n;i++)        if(a[i]<mn)            mn=a[i],pos=i;    cout<<pos<<endl;    return 0;}

2.矩阵

问题描述

豆豆在玩一个N行M咧的矩阵,他现在需要从中选出恰好K个不互相重叠的非空子矩阵。他的得分为这些子矩阵的数值之和。他想知道他最多能得多少分?

输入格式

第一行为N,M,K表示矩阵的行数和列数以及K值。
接下来K行,每行M个数字描述矩阵每行中的每个元素的数值。

输出格式

输出一个整数表示最多的得分。

输入样例

3 2 2
1 -3
2 3
-2 3

输出样例

9

数据范围

对于20%的数据,M≤1,K≤1;
对于50%的数据,M≤1,K≤10;
对于另外10%的数据,0≤数值;
对于100%的数据,1≤N≤100,1≤M≤2,1≤K≤10,|数值|≤1000000。

用动态规划,分两种情况讨论。
一种是m=1,开一个二维数组f[i][j],表示当前处理了i个数,已经用了j个矩阵时能够获得的最大值
状态转移方程:f[i][j]=max(f[i][j],f[j][i-1]+a[i]-a[j])
还有一种m=2,开一个三维数组f[i][j][k]表示扫描到第一列i位置与第二列j位置且选取k个矩阵的答案。
转移有三种:第一列取一段,第二列取一段,取一个宽度为2的矩阵。

#include<iostream>#include<cstdlib>#include<cstdio>#include<cstring>#include<string>#include<ctime>#include<cmath>#include<algorithm>#include<cctype>#include<iomanip>using namespace std;int n,m,k,ans;int a[110][4],f1[110][110],f2[110][110][110];inline int read(){    int i=0,f=1;    char c;    for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());    if(c=='-')        f=-1,c=getchar();    for(;c>='0'&&c<='9';c=getchar())        i=(i<<1)+(i<<3)+c-'0';    return i*f;}inline void zql(){    memset(f1,-10,sizeof(f1));    for(int i=0;i<=n;i++)        f1[i][0]=0;    for(int i=1;i<=n;i++)        for(int j=1;j<=k;j++)        {            f1[i][j]=f1[i-1][j];            for(int t=0;t<=i-1;t++)                f1[i][j]=max(f1[i][j],f1[t][j-1]+a[i][1]-a[t][1]);        }    ans=f1[n][k];}inline void zzk(){    memset(f2,-10,sizeof(f2));    for(int i=0;i<=n;i++)        for(int j=0;j<=n;j++)            f2[i][j][0]=0;    for(int i=1;i<=n;i++)        for(int j=1;j<=n;j++)            for(int t=1;t<=k;t++)            {                f2[i][j][t]=max(f2[i-1][j][t],f2[i][j-1][t]);//第一行。                for(int p=0;p<=i-1;p++)                    f2[i][j][t]=max(f2[i][j][t],f2[p][j][t-1]+a[i][1]-a[p][1]);//第二行。                for(int p=0;p<=j-1;p++)                    f2[i][j][t]=max(f2[i][j][t],f2[i][p][t-1]+a[j][2]-a[p][2]);                if(i==j)                    for(int p=0;p<=i-1;p++)                        f2[i][j][t]=max(f2[i][j][t],f2[p][p][t-1]+a[i][1]-a[p][1]+a[i][2]-a[p][2]);            }//取一个宽度为2的矩阵。    ans=f2[n][n][k];}int main(){    //freopen("matrix.in","r",stdin);    //freopen("matrix.out","w",stdout);    n=read(),m=read(),k=read();    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)            a[i][j]=read(),a[i][j]+=a[i-1][j];    if(m==1) zql();    if(m==2) zzk();    cout<<ans<<endl;    return 0;}

3.裁剪表格

问题描述

豆豆有一个n行m列的表格,每个格子里都有一个数字v。
豆豆学完了高级数据结构后,想拿这个表格练手。
所以他想出了这么一个问题:
每次在表格中取出不相邻(不相邻是指不相交且没有共同的边界,但是可以有一样的顶点)的两个大小一样的子矩阵,然后交换这两个子矩阵。这样操作q次之后,这个原有表格会变成什么样子?

输入格式

第一行三个整数n,m,q代表表格的行数和列数以及操作次数。
接下来n行,每行m个整数,表示表格中的数字。
接下来q行,每行六个整数r1,c1,r2,c2,h,w分别表示第一个矩形左上角所在行、所在列,第二个矩形左上角所在行、所在列,这两个矩形的高度和宽度(保证这两个矩形都在原有表格内)。

输出格式

输出n行,每行m个整数,表示最终表格中的数字,用空格隔开。

输入样例

4 4 2
1 1 2 2
1 1 2 2
3 3 4 4
3 3 4 4
1 1 3 3 2 2
3 1 1 3 2 2

输出样例

4 4 3 3
4 4 3 3
2 2 1 1
2 2 1 1

数据范围

对于10%的数据,所有的v=1;
对于30%的数据,n,m≤300,q≤300;
对于60%的数据,n,m≤1000,q≤500;
对于100%的数据,2≤n,m≤1000,1≤q≤10000,1≤v≤1000000。

这道题真的不想多说,暴力直接过,100分。

#include<iostream>#include<cstdlib>#include<cstdio>#include<cstring>#include<string>#include<ctime>#include<cmath>#include<algorithm>#include<cctype>#include<iomanip>using namespace std;int n,m,q,r1,c1,r2,c2,h,w;int s[3300][3300];inline int read(){    register int i=0,f=1;    char ch=getchar();    for(ch;ch>'9'||ch<'0'&&ch!='-';ch=getchar());    if(ch=='-')        ch=getchar(),f=-1;    for(ch;ch>='0'&&ch<='9';ch=getchar())        i=(i<<1)+(i<<3)+ch-'0';    return i*f;}int main(){    n=read(),m=read(),q=read();    for(register int i=1;i<=n;i++)        for(register int j=1;j<=m;j++)            s[i][j]=read();    while(q--)    {        r1=read(),c1=read(),r2=read(),c2=read(),h=read(),w=read();        for(register int i=0;i<h;i++)            for(register int j=0;j<w;j++)                swap(s[r1+i][c1+j],s[r2+i][c2+j]);    }    for(register int i=1;i<=n;i++)    {        for(register int j=1;j<=m;j++)            cout<<s[i][j]<<" ";        cout<<endl;    }    return 0;}

以上。
来自2017.10.20.

——我认为return 0,是一个时代的终结。

原创粉丝点击