codeforces contest 479

http://codeforces.com/contest/479

ABC水题就不说了

//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

D 479D Long Jumps

题意:有一个长l的刻度尺上面有n个刻度,补充最少的刻度使得可以从上面读出x,y

题解:

如果两个都能找到,不用补充。

找到一个,补充一个。

找到y-x,如果它满足需补充的刻度不超过刻度尺,补充一个。

找到x+y,补充一个。

否则,补充两个。

可以用滑窗找需要找的长度。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define de(x) cout << #x << "=" << x << endl
int a[200005];
int main() {
    int n,l,x,y;
    while(~scanf("%d%d%d%d",&n,&l,&x,&y)) {
        for(int i=1;i<=n;++i) scanf("%d",&a[i]);
        bool okx=0,oky=0;
        for(int i=1,j=1;j<=n;++j) {
            while(i<j&&a[j]-a[i]>x) ++i;
            if(a[j]-a[i]==x) {
                okx=1;break;
            }
        }
        for(int i=1,j=1;j<=n;++j) {
            while(i<j&&a[j]-a[i]>y) ++i;
            if(a[j]-a[i]==y) {
                oky=1;break;
            }
        }
        int z=y-x;
        int okz=0;
        for(int i=1,j=1;j<=n;++j) {
            while(i<j&&a[j]-a[i]>z) ++i;
            if(a[j]-a[i]==z&&(a[j]+x<=l||a[j]-y>=0)) {
                okz=a[j];break;
            }
        }

        int t=x+y;
        int okt=0;
        for(int i=1,j=1;j<=n;++j) {
            while(i<j&&a[j]-a[i]>t) ++i;
            if(a[j]-a[i]==t) {
                okt=a[j];break;
            }
        }

        if(okx&&oky) {
            puts("0");
        } else if(okx&&!oky) {
            printf("1\n%d\n",y);
        } else if(oky&&!okx) {
            printf("1\n%d\n",x);
        } else if(!okx&&!oky) {
            if(okz&&okz+x<=l) {
                printf("1\n%d\n",okz+x);
            } else if(okz&&okz-z-x>=0) {
                printf("1\n%d\n",okz-z-x);
            } else if(okt) {
                printf("1\n%d\n",okt-x);
            } else {
                printf("2\n%d %d\n",x,y);
            }
        }
    }
    return 0;
}


//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

E  479E  Riding in a Lift
题意:有一个电梯,运行范围是1~n,初始在a层,停靠k次,问有几种可能。从x层停靠到y层停靠需要满足条件 |x - y| < |x - b|。
题解:一开始算错复杂度了,想的是暴搜,对于当前位置,枚举所有可能的位置,递归下去。(还存下了d[x][k]的值,并没有什么用。)然后就T了。算一下复杂度,发现很爆炸= = 
又想到一种解法,对于k停靠的每个点,它对k+1停靠的点的一段区间是可达到。所以我们只要从1到k,算一下有第k次的点被到达了几次,就能求出解。这样就涉及到区间增减的问题。如果利用数组之间的差分,每次区间增减所需时间只有O(1)。总复杂度是k(每次)*n(该次的所有点)。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define de(x) cout << #x << "=" << x << " "
const int mod=1000000007;
const int N=5005;
int n,a,b,k;
ll d[N][N];
int main() {
    while(~scanf("%d%d%d%d",&n,&a,&b,&k)) {
        memset(d,0,sizeof(d));
        d[0][a]=1;
        for(int i=1;i<=k;++i) {
            for(int j=1;j<=n;++j) {
                if(d[i-1][j]) {//如果上面有,就把它映射到下一级
                    int l1,r1=j-1,l2=j+1,r2,bb=b-2*(b-j);
                    if(bb<0) bb=0;
                    if(bb>n+1) bb=n+1;
                    if(j<b) {
                        l1=bb+1;
                        r2=b-1;
                    } else {
                        l1=b+1;
                        r2=bb-1;
                    }
                    if(l1<=r1) {
                        d[i][l1]=(d[i][l1]+d[i-1][j])%mod;
                        d[i][r1+1]=(d[i][r1+1]-d[i-1][j])%mod;
                    }
                    if(l2<=r2) {
                        d[i][l2]=(d[i][l2]+d[i-1][j])%mod;
                        d[i][r2+1]=(d[i][r2+1]-d[i-1][j])%mod;
                    }
                }
            }
            for(int j=1;j<=n;++j) d[i][j]=((d[i][j-1]+d[i][j])%mod+mod)%mod;
        }
        ll ans=0;
        for(int i=1;i<=n;++i) ans=(ans+d[k][i])%mod;
        printf("%I64d\n",ans);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值