10月集训test10

又是写考试总结的时候了。。。。
这次考试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,是一个时代的终结。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值