刷题集合3

 99. 激光炸弹

一种新型的激光炸弹,可以摧毁一个边长为R的正方形内的所有的目标。
现在地图上有n(N ≤ 10000)个目标,用整数Xi,Yi(其值在[0,5000])表示目标在地图上的位置,每个目标都有一个价值。
激光炸弹的投放是通过卫星定位的,但其有一个缺点,就是其爆破范围,即那个边长为R的正方形的边必须和x,y轴平行。
若目标位于爆破正方形的边上,该目标将不会被摧毁。

输入描述
输入文件的第一行为正整数n和正整数R,接下来的n行每行有3个正整数,分别表示 xi,yi ,vi 。

输出描述
输出文件仅有一个正整数,表示一颗炸弹最多能炸掉地图上总价值为多少的目标(结果不会超过32767)。

示例1

输入

2 1
0 0 1
1 1 1

输出

1

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N=5500;
int s[N][N],res;
int n,r,mx,my;

int main()
{
    scanf("%d%d",&n,&r);
    r=min(r,5001);
    mx=5100,my=5100;
    for(int i=0;i<n;i++)
    {
        int x,y,w;
        scanf("%d%d%d",&x,&y,&w);
        x++,y++;
        s[x][y]+=w;
        mx=max(mx,x);
        my=max(my,y);
    }

    for(int i=1;i<=mx;i++)
    {
        for(int j=1;j<=my;j++)
        {
            s[i][j]+=+s[i-1][j]+s[i][j-1]-s[i-1][j-1];
        }
    }

    if(r>mx&&r>my) res = s[mx][my];
    else 
    {
        for(int i=r;i<=mx;i++)
            for(int j=r;j<=my;j++)
            {
                res=max(res,s[i][j]-s[i-r][j]-s[i][j-r]+s[i-r][j-r]);
            }
    }
    cout<<res;
}

1230. K倍区间 

资源限制

时间限制:1.0s 内存限制:256.0MB

  给定一个长度为N的数列,A1, A2, ... AN,如果其中一段连续的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍区间。

  你能求出数列中总共有多少个K倍区间吗?

输入格式

  -----
  第一行包含两个整数N和K。(1 <= N, K <= 100000)
  以下N行每行包含一个整数Ai。(1 <= Ai <= 100000)

输出格式

  -----
  输出一个整数,代表K倍区间的数目。


  例如,

输入格式

  5 2
  1
  2
  3
  4
  5

  程序应该输出:
  6

本题直接想法是暴力枚举,固定左右端点,对区间和的数相加判断是否是k的倍数,算法复杂度太高;

对于内层循环,可以用前缀和减少运算量;

对于右侧每个r,我们有在1到r上,找出(s[r]-s[l-1])是k的倍数的左端点即可,0到r-1上;s[r]与s[l]的余数相同的端点满足要求,也就是求与每一个s[r]%k相同的在r之前的数的个数,可以通过一个数组记录s[r]%k的个数。最后通过循环算出,需要注意的是,s[r]%k余数为0的书本身就可以作为k的倍数的区间,因此需要算入s[r]的个数。

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int a[N],s[N],res[N];
int n,k;
int main(){
    cin>>n>>k;
    long long ans=0;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        s[i]=(s[i-1]+a[i])%k;
        ans+=res[s[i]];
        res[s[i]]++;
    }
    cout<<ans+res[0];
}

买不到的数目
问题描述
小明开了一家糖果店。

他别出心裁:把水果糖包成4颗一包和7颗一包的两种。

糖果不能拆包卖。

小朋友来买糖的时候,他就用这两种包装来组合。

当然有些糖果数目是无法组合出来的,比如要买 10 颗糖。

你可以用计算机测试一下,在这种包装情况下,最大不能买到的数量是17。

大于17的任何数字都可以用4和7组合出来。

本题的要求就是在已知两个包装的数量时,求最大不能组合出的数字。

输入格式
两个正整数 n,m,表示每种包装中糖的颗数。

输出格式
一个正整数,表示最大不能买到的糖数。

数据范围

2≤n,m≤1000,

保证数据一定有解。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int main(){
    int m,n;
    cin>>m>>n;
    cout<<m*n-m-n;
    
}

 蚂蚁感冒

长 100厘米的细长直杆子上有 n 只蚂蚁。

它们的头有的朝左,有的朝右。

每只蚂蚁都只能沿着杆子向前爬,速度是 1厘米/秒。

当两只蚂蚁碰面时,它们会同时掉头往相反的方向爬行。

这些蚂蚁中,有 1只蚂蚁感冒了。

并且在和其它蚂蚁碰面时,会把感冒传染给碰到的蚂蚁。

请你计算,当所有蚂蚁都爬离杆子时,有多少只蚂蚁患上了感冒。

输入格式

第一行输入一个整数 n, 表示蚂蚁的总数。

接着的一行是 n 个用空格分开的整数 Xi, Xi 的绝对值表示蚂蚁离开杆子左边端点的距离。

正值表示头朝右,负值表示头朝左,数据中不会出现 0 值,也不会出现两只蚂蚁占用同一位置。

其中,第一个数据代表的蚂蚁感冒了。

输出格式

输出1个整数,表示最后感冒蚂蚁的数目。

数据范围

1<n<50
0<|Xi|<100

输入样例1:

3
5 -2 8
输出样例1:

1
输入样例2:

5
-10 8 -20 12 25
 

输出样例2:

3

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int x[51];
int main(){
      int n,ans=0;
      cin>>n;
      for(int i=0;i<n;i++){
          cin>>x[i];
      }
      int left=0,right=0;
      for(int i=0;i<n;i++){
          if(abs(x[0])<abs(x[i])&&x[i]<0)right++;
          if(abs(x[0])>abs(x[i])&&x[i]>0)left++;
      }
 if(x[0]<0&&!left||x[0]>0&&!right){
     ans=1;
 }
 else{
     ans+=left+right+1;
 }
      
    
      cout<<ans;
    
}

蓝桥杯–饮料换购
乐羊羊饮料厂正在举办一次促销优惠活动。乐羊羊C型饮料,凭3个瓶盖可以再换一瓶C型饮料,并且可以一直循环下去,但不允许赊账。

请你计算一下,如果小明不浪费瓶盖,尽量地参加活动,那么,对于他初始买入的n瓶饮料,最后他一共能得到多少瓶饮料。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int main(){
    int tot=0,s=0,ans;
    cin>>tot;
    ans=tot;
    while(tot/3>0){
      ans+=tot/3;// 可换数
      tot=tot/3+tot%3; //可换数+剩余瓶盖数目;
    }
    
    cout<<ans;
}

 摘花生

Hello Kitty想摘点花生送给她喜欢的米老鼠。
她来到一片有网格状道路的矩形花生地(如下图),从西北角进去,东南角出来。

地里每个道路的交叉点上都有种着一株花生苗,上面有若干颗花生,经过一株花生苗就能摘走该它上面所有的花生。
Hello Kitty只能向东或向南走,不能向西或向北走。
问Hello Kitty最多能够摘到多少颗花生。
输入格式
第一行是一个整数T,代表一共有多少组数据。
接下来是T组数据。
每组数据的第一行是两个整数,分别代表花生苗的行数R和列数 C。
每组数据的接下来R行数据,从北向南依次描述每行花生苗的情况。每行数据有C个整数,按从西向东的顺序描述了该行每株花生苗上的花生数目M。
输出格式
对每组输入数据,输出一行,内容为Hello Kitty能摘到得最多的花生颗数。
数据范围
1≤T≤100,1≤R,C≤100,0≤M≤1000
输入样例:
2
2 2
1 1
3 4
2 3
2 3 4
1 6 5
输出样例:
8
16

#include<iostream>//递推性
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=101;
int t;
int s[N][N];

int main(){
    cin>>t;
    while(t--){
        int n,m;
        cin>>n>>m;
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                cin>>s[i][j];
                if(i==0&&j==0){
                    s[i][j]=s[i][j];}
                else if(i==0){
                    s[i][j]=s[i][j-1]+s[i][j];
                }
                else if(j==0){
                    s[i][j]=s[i-1][j]+s[i][j];
                }
                else {s[i][j]=max(s[i-1][j],s[i][j-1])+s[i][j];}
                }
            }
        
        cout<<s[n-1][m-1]<<endl;
    }
}
#include<iostream>  //递归型
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=101;
int t;
int d[N][N],s[N][N];
int  dfs(int x,int y){
    if(x<1||y<1){
        return 0;
    }
    if(s[x][y]!=-1){
        return s[x][y];
    }
    else{  if(x==1&&y==1){
        return d[x][y];
    }
          s[x][y]=max(dfs(x-1,y),dfs(x,y-1))+d[x][y];
    return s[x][y];}
}
int main(){
    cin>>t;
    while(t--){
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                cin>>d[i][j];
                s[i][j]=-1;
            }
        }
        cout<<dfs(n,m)<<endl;
    }
}

01背包问题

问题描述

01背包问题可描述为如下问题:
有一个容量为V的背包,还有n个物体。现在忽略物体实际几何形状,我们认为只要背包的剩余容量大于等于物体体积,那就可以装进背包里。每个物体都有两个属性,即体积w和价值v。
问:如何向背包装物体才能使背包中物体的总价值最大?

#include<bits/stdc++.h>

using namespace std;

const int MAXN = 1005;
int v[MAXN];    // 体积
int w[MAXN];    // 价值 
int f[MAXN][MAXN];  // f[i][j], 总体积不超过j体积前i个物品的所有方案最大价值 



int main() 
{   int n,m;
cin>>n>>m;
   for(int i=1;i<=n;i++){
       cin>>v[i]>>w[i];
   }
   for(int i=1;i<=n;i++){
       for(int j=0;j<=m;j++){
           if(j<v[i]){
               f[i][j]=f[i-1][j];
           }
           else{
               f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]);
           }
       }
   }
   cout<<f[n][m];
}

#include<bits/stdc++.h>

using namespace std;

const int MAXN = 1005;
int v[MAXN];    // 体积
int w[MAXN];    // 价值 
int f[MAXN];  //


int main() 
{   int n,m;
cin>>n>>m;
   for(int i=1;i<=n;i++){
       cin>>v[i]>>w[i];
   }
   for(int i=1;i<=n;i++){
       for(int j=m;j>=v[i];j--){
          
               f[j]=max(f[j],f[j-v[i]]+w[i]);
           
       }
   }
   cout<<f[m];
}

 最长上升子序列

给出一个由 n(n≤5000) 个不超过 1e6 的正整数组成的序列。请输出这个序列的最长上升子序列的长度。

最长上升子序列是指,从原序列中按顺序取出一些数字排在一起,这些数字是逐渐增大的。

输入格式

第一行,一个整数 n,表示序列长度。

第二行有 n 个整数,表示这个序列。

输出格式

一个整数表示答案。

输入输出样例

输入 

6
1 2 4 1 3 4

输出 

4

#include<iostream> 
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[5001],s[5001];
int main(){
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    
    for(int i=0;i<n;i++){
        s[i]=1;
        for(int j=0;j<i;j++){
            if(a[j]<a[i]){
                s[i]=max(s[i],s[j]+1);
            }
        }
    }int ans=0;
    for(int i=0;i<n;i++){
        ans=max(s[i],ans);
    }
    cout<<ans<<endl;
}

1 地宫寻宝
X 国王有一个地宫宝库,是 n×m 个格子的矩阵,每个格子放一件宝贝,每个宝贝贴着价值标签。

地宫的入口在左上角,出口在右下角。

小明被带到地宫的入口,国王要求他只能向右或向下行走。

走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。

当小明走到出口时,如果他手中的宝贝恰好是 k 件,则这些宝贝就可以送给小明。

请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这 k 件宝贝。

输入格式
第一行 3 个整数,n,m,k,含义见题目描述。

接下来 n 行,每行有 m 个整数 Ci 用来描述宝库矩阵每个格子的宝贝价值。

输出格式
输出一个整数,表示正好取 k 个宝贝的行动方案数。

该数字可能很大,输出它对 1000000007 取模的结果。

数据范围
1≤n,m≤50,
1≤k≤12,
0≤Ci≤12
输入样例1:
2 2 2
1 2
2 1
输出样例1:
2
输入样例2:
2 3 2
1 2 3
2 1 5
输出样例2:
14

#include<iostream>  //递归
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=51,mod=1000000007;
int f[N][N][13][14];//从开始到 i,j位置所取得的宝物数为k,最后一件取得价值为c的宝物的所有集合的方案
int a[N][N];
int n,m,k;
int main(){
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
            a[i][j]++;
        }
    }
    f[1][1][1][a[1][1]]=1;
    f[1][1][0][0]=1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(i==1&&j==1)
            continue;
            for(int u=0;u<=k;u++){
                for(int v=0;v<=13;v++){
                    int &val=f[i][j][u][v];
                    val=(val+f[i-1][j][u][v])%mod;
                    val=(val+f[i][j-1][u][v])%mod;
                    if(u>0&&v==a[i][j]){
                    for(int w=0;w<v;w++){
                        val=(val+f[i-1][j][u-1][w])%mod;
                        val=(val+f[i][j-1][u-1][w])%mod;
                    }
                    }
                }
            }
        }
    }
    int ans=0;
    for(int i=0;i<=13;i++){
        ans=(ans+f[n][m][k][i])%mod;
    }
    cout<<ans<<endl;
    
}

 波动数列

问题描述
观察如下数列:
1 3 0 2 -1 1 -2 …
这个数列中后一项总是比前一项增加 2 或者减少 3。
栋栋对这种数列很好奇,他想知道长度为 n  和为 s  而且后一项总是比前一项增加 a或者减少 b  的整数数列可能有多少种呢?

输入格式
输入的第一行包含四个整数 n   s   a   b ,含义如前面说述。

输出格式
输出一行,包含一个整数,表示满足条件的方案数。由于这个数很大,请输出方案数除以 100000007 的余数。

样例输入
4 10 2 3

样例输出
2

#include<iostream>  
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int mod=100000007;
int f[1001][1001]; //前i个数,所有总和除n的余数是j的所有集合
int get_mod(int a,int b){
    return (a%b+b)%b;
}
int main(){
    int n,s,a,b;
    cin>>n>>s>>a>>b;
 
    f[0][0]=1;
    for(int i=1;i<=n;i++){
        for(int j=0;j<n;j++){
             f[i][j]=(f[i-1][get_mod(j+b*i,n)]+f[i-1][get_mod(j-a*i,n)])%mod;
        }
       
    }
    cout<<f[n-1][get_mod(s,n)]<<endl;
    
}

连号区间数
小明这些天一直在思考这样一个奇怪而有趣的问题:
在1~N的某个全排列中有多少个连号区间呢?这里所说的连号区间的定义是:
如果区间[L, R] 里的所有元素(即此排列的第L个到第R个元素)递增排序后能得到一个长度为R-L+1的“连续”数列,则称这个区间连号区间。
当N很小的时候,小明可以很快地算出答案,但是当N变大的时候,问题就不是那么简单了,现在小明需要你的帮助。
输入格式:
第一行是一个正整数N (1 <= N <= 50000), 表示全排列的规模。
第二行是N个不同的数字Pi(1 <= Pi <= N), 表示这N个数字的某一全排列。
输出格式:
输出一个整数,表示不同连号区间的数目。
示例:
用户输入:
4
3 2 4 1
程序应输出:
7
用户输入:
5
3 4 2 5 1
程序应输出:
9
解释:
第一个用例中,有7个连号区间分别是:[1,1], [1,2], [1,3], [1,4], [2,2], [3,3], [4,4]
第二个用例中,有9个连号区间分别是:[1,1], [1,2], [1,3], [1,4], [1,5], [2,2], [3,3], [4,4], [5,5]

#include<iostream>  
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e4;
int a[N];


int main(){
    int n,ans=0;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
     for(int i=0;i<n;i++){
         int max1=-1;
         int min1=1000000;
    
         for(int j=i;j<n;j++){
             
                 max1=max(max1,a[j]);
                 min1=min(min1,a[j]);
                 if(max1-min1==j-i){
                     ans++;
                 }
             }
         }
     
    cout<<ans;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值