CodeForces 607A Chain Reaction

题意是有一系列塔,每个塔位置不同攻击范围不同,塔只攻击右侧,范围内的(包括边界塔不包括本身);按从右到左的顺序点燃,被破坏掉的将不能点燃;要求:在最右侧再添一个塔并第一个点燃,使破坏掉的塔的数目最少

涉及递推,2ms时限,优化3次ac

!!不考虑新加的塔《给出一系列塔的位置和破坏范围,(ps:自己把它当成一个串觉的好理解)可求出这一系列(这个串)当点燃时破环的塔数》。

//在暴力枚举中发现可以递推
#include<cstdio>
#include<iostream>
using namespace std;
const int N=1000005; //一百万的值
const int Max=99999999;
int a[N]; //下标记录塔的位置对应值记录攻击范围
int b[N];//记录从0到下标位置(下标位置被点燃后)(这个串)要破坏塔的数量
int book[N];//记录对应下标位置是否有塔
int main(){
int n;
scanf("%d",&n);
for(int i=0;i<n;i++) 
{
    int x,y;
    scanf("%d%d",&x,&y);
    a[x]=y;
    book[x]=1;    //book不可少 万一攻击范围为零
}
int num=0,maxn=Max,k=0;
for(int i=0;i<N;i++) //按从左到右的方向找塔
{
    if(book[i]){     //枚举每个塔  这时已假设塔右方的所有塔已被新添加的塔破坏掉了
             num++;
            int sum=0;
        for(int j=i-1;j>=i-a[i]&&j>=0;j--) //在这个塔攻击范围里有几个塔(这些塔将被摧毁)
        {
            if(book[j]) sum++;
        }
        for(int j=i-a[i]-1;j>=0;j--)  
        {
            if(book[j]) {b[i]+=b[j];break;} //攻击范围外的第一个塔(前一个串的值)递推公式:b[i]=b[j]+sum;
        }
        b[i]+=sum;
        if(b[i]+n-num<maxn) maxn=b[i]+n-num;  //求出的b[i]值加右侧被被破坏的塔得到完整的值
    }
}
printf("%d\n",maxn);
return 0;
}
//以为if判断会很快结果超时
初次:
//优化,代码可以很简便但超时
//不再用一百万数组的下标记录塔而直接用十万的结构体储存
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N=100005;
const int Max=999999999;
struct f{
int x,y;
}a[N];
int b[N];
bool cmp(f p,f q){
return p.x<q.x;
}
int main(){
    int n;
    scanf("%d",&n);
     for(int i=0;i<n;i++)
       scanf("%d%d",&a[i].x,&a[i].y);
     sort(a,a+n,cmp);
     int maxn=Max;
     for(int i=0;i<n;i++)
     {
         int j,sum=0;
         for(j=i-1;j>=0;j--)
         {
             if(a[j].x>=a[i].x-a[i].y){sum++;}
             else break;
         }
         if(j>=0) b[i]+=b[j]+sum;
         if(b[i]+n-(i+1)<maxn) maxn=b[i]+n-(i+1);
     }
     printf("%d\n",maxn);
return 0;
}
AC:
//空间换时间添加2个一百万的数组,用两种方式记录数据
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N=100005;
const int M=1000005;
const int Max=999999999;
struct f{
int x,y;
}a[N];   // 记录数据的数组(1)
int b[N]; //递推数组
int c[M]; // 第一个代码的记录方式(2) 
int num[M]; //到下标位置塔的数量
bool cmp(f p,f q){
return p.x<q.x;
}
int main(){
    int n;
    scanf("%d",&n);
     for(int i=1;i<=n;i++)
       {
           scanf("%d%d",&a[i].x,&a[i].y);
           c[a[i].x]=a[i].y;
       }
       int s=0;
       for(int i=0;i<M;i++) //预处理
       {
           if(c[i]){s++;}
           num[i]=s; 
       }
     sort(a+1,a+n+1,cmp);
     int maxn=Max;
     for(int i=1;i<=n;i++)  //一百万 到 十万
     {
           int p;
           if(a[i].x-a[i].y-1>=0) p=num[a[i].x-1]-num[a[i].x-a[i].y-1]; //一百万 到 一 内层循环处理掉
           else p=num[a[i].x-1];
                   b[i]+=p; //p相当于上个的sum
           if(i-p-1>=0) b[i]+=b[i-p-1];//这个相当于上个的b[j]
         if(b[i]+n-i<maxn) maxn=b[i]+n-i; //完整值
     }
     printf("%d\n",maxn);
return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值