http://codeforces.com/contest/479
ABC水题就不说了
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
题意:有一个长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;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
题解:一开始算错复杂度了,想的是暴搜,对于当前位置,枚举所有可能的位置,递归下去。(还存下了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;
}