这个是题干:https://www.luogu.org/problemnew/show/P1052#sub
这是一道NOIP2005年的提高组的题,那道题一看,就是要用动态规划,状态转移方程也十分简单。只需要考虑是从哪个地方来的,看看即将到达的点是否有石子。用一维数组 f[x] 表示第X位的步数(额,这只是30分的写法,L 的取值太大,数组承受不了)
之后,我又想骗一点分,就特判了一下s==t的情况,结果竟然又过了一个点,简直就是玄学。。。
#include<iostream>
#include<cstring>
using namespace std;
const int maxN=20000100;
int l,s,t,m,ans,f[maxN],b[110];
bool a[maxN];
void prepare()
{
memset(f,-1,sizeof(f));
f[0]=0;
for(int i=s;i<=l+t-1;++i){
for(int j=s;j<=min(t,i);++j){
if(f[i-j]==-1)
continue;
if(f[i]==-1||f[i-j]+a[i]<f[i])
f[i]=f[i-j]+a[i];
}
}
}
void work()
{
f[0]=0;
for(int i=1;i<=m;++i){
if(b[i]%s==0)
ans++;
}
}
int main()
{
cin>>l>>s>>t>>m;
for(int i=1;i<=m;++i)
cin>>b[i];
if(s==t){
work();
cout<<ans<<endl;
return 0;
}
for(int i=1;i<=m;++i)
a[b[i]]=true;
prepare();
int ans=maxN;
for(int i=l;i<=l+t-1;++i){
if(f[i]!=-1){
ans=min(ans,f[i]);
}
}
cout<<ans<<endl;
return 0;
}
在这里,需要用到一个神奇的的定理,也就是小凯的烦恼(2017年提高组第一题)需要用到的。定理描述如下
有两个互质的自然数p,q,不能用p*x+q*y表示的最大整数是
p*q+-p-q(x,y均为正整数)
有兴趣的可以证明一下~~~
言归正传,如果两个石子相离很远,那么他们之间都可以随意走动,步数不增加,走100000步没用的其实和走100步没用的效果是一样的(都是没用。。)
所以当两块石子的距离超过了没用距离(即(t-1)*t)时,直接将两石子的距离缩短为这个值(但是经本蒟蒻的深思熟虑,发现还是有风险有特例的(或者自己考虑不周,如果有大犇可以解释,请留言教一下本蒟蒻,谢谢!!!))
最后附上代码:
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<utility>
using namespace std;
const int maxN=100000;
int l,s,t,m,ans,st,f[maxN],b[maxN];
bool a[maxN];
void qsort(int l,int r)
{
if(l>=r)
return;
int t=b[rand()%(r-l+1)+l];
int i=l,j=r;
while(i<=j){
while(b[i]<t)i++;
while(b[j]>t)j--;
if(i<=j){
swap(b[i],b[j]);
i++;
j--;
}
}
qsort(l,j);
qsort(i,r);
}
void prepare()
{
memset(f,-1,sizeof(f));
f[0]=0;
for(int i=s;i<=st+t-1;++i){
for(int j=s;j<=min(t,i);++j){
if(f[i-j]==-1)
continue;
if(f[i]==-1||f[i-j]+a[i]<f[i])
f[i]=f[i-j]+a[i];
}
}
}
void work()
{
f[0]=0;
for(int i=1;i<=m;++i){
if(b[i]%s==0)
ans++;
}
}
int main()
{
cin>>l>>s>>t>>m;
for(int i=1;i<=m;++i)
cin>>b[i];
srand(100000);
qsort(1,m);
if(s==t){
work();
cout<<ans<<endl;
return 0;
}
b[m+1]=l;
int add=(t-1)*t;
for(int i=1;i<=m+1;++i){
if((b[i]-b[i-1])>add){
st+=add;
a[st]=true;
}
else{
st+=(b[i]-b[i-1]);
a[st]=true;
}
}
prepare();
int ans=maxN;
for(int i=st;i<=st+t-1;++i)
if(f[i]!=-1)
ans=min(ans,f[i]);
cout<<ans<<endl;
return 0;
}