动态规划
先按照高度h从小到大排序
f [ i ] [ j ] f[i][j] f[i][j]表示最后一次从第i个节点跳,一共跳了j次的最小代价
状态转移方程:
f [ i ] [ j ] = m i n ( f [ i ] [ j ] , f [ k ] [ j − 1 ] + a [ k ] . c ) f[i][j]=min(f[i][j],f[k][j-1]+a[k].c) f[i][j]=min(f[i][j],f[k][j−1]+a[k].c) ( k < i ) (k(k<i)
统计答案时,按 j j j从大到小枚举,若能找到 f [ i ] [ j ] + a [ i ] . c < = t f[i][j]+a[i].c<=t f[i][j]+a[i].c<=t,则 j + 1 j+1 j+1则为最多跳的次数(ps:加上了最后一次跳到地面的花费和次数)
#include<bits/stdc++.h>
using namespace std;
const int N=100,inf=0x3f3f3f3f;
int n,t;
int f[N][N];
struct node{
int h,c;
}a[N];
int read(){
int sum=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return sum*f;
}
void print(int x)
{
if(x<0)x=-x,putchar('-');
if(x>9)print(x/10);
putchar(x%10+'0');
}
bool comp(node a,node b){
return a.h<b.h;
}
int main(){
n=read();
for(int i=1;i<=n;i++)
a[i].c=read();
for(int i=1;i<=n;i++)
a[i].h=read();
t=read();
sort(a+1,a+n+1,comp);
memset(f,inf,sizeof(f));
for(int i=1;i<=n;i++)f[i][0]=a[i].c;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
for(int k=1;k<i;k++)
f[i][j]=min(f[i][j],f[k][j-1]+a[k].c+abs(a[i].h-a[k].h));
for(int j=n;j>=0;j--)
for(int i=1;i<=n;i++)
if(f[i][j]<=t){print(j+1);return 0;}
return 0;
}
找规律+枚举
c [ ] c[] c[]表示两两的和, a [ ] a[] a[]表示每一个数
先对 c [ ] c[] c[]从小到大排序,易知:
c [ 1 ] = a [ 1 ] + a [ 2 ] c[1]=a[1]+a[2] c[1]=a[1]+a[2]
c [ 2 ] = a [ 1 ] + a [ 3 ] c[2]=a[1]+a[3] c[2]=a[1]+a[3]
设 c [ x ] = a [ 2 ] + a [ 3 ] c[x]=a[2]+a[3] c[x]=a[2]+a[3]枚举x (3<=x<=n*(n-1)/2)
由以上三个式子解出a[1],a[2],a[3],并删去c[1],c[2],c[x]。
此时c[]中最小的数为 c [ j ] = a [ 1 ] + a [ 4 ] c[j]=a[1]+a[4] c[j]=a[1]+a[4],解出a[4]。
在 c [ ] c[] c[]中查找并删去 a [ i ] + a [ 4 ] ( 1 < = i < 4 ) a[i]+a[4](1<=i<4) a[i]+a[4](1<=i<4),然后 c [ ] c[] c[]中最小的数为 c [ j ] = a [ 1 ] + a [ 5 ] c[j]=a[1]+a[5] c[j]=a[1]+a[5],解出 a [ 5 ] a[5] a[5]…
以此类推,直到解出所有解。
若中途在 c [ ] c[] c[]中查到不到相应的数,则当前x的情况不合法,直接退出。
#include<bits/stdc++.h>
using namespace std;
const int N=305,inf=0x3f3f3f3f;
int n,m,tot;
int c[N*N],a[305],ans[N*N][305],v[N*N];
int read(){
int sum=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return sum*f;
}
void print(int x)
{
if(x<0)x=-x,putchar('-');
if(x>9)print(x/10);
putchar(x%10+'0');
}
void solve(int x){
memset(v,0,sizeof(v));
if((c[1]+c[x]-c[2])&1)return;
a[2]=(c[1]+c[x]-c[2])>>1;
a[1]=c[1]-a[2];
a[3]=c[x]-a[2];
v[1]=v[2]=v[x]=1;
int k=4;
for(int i=3;i<=m;i++)
{
if(v[i])continue;
a[k]=c[i]-a[1];
for(int j=1;j<k;j++){
int q=a[j]+a[k];
int x=lower_bound(c+1,c+m+1,q)-c;
if(c[x]!=q)return;
while(v[x]&&x<m&&c[x]==q)x++;
if(c[x]!=q)return;
v[x]=1;
}
k++;
}
tot++;
for(int i=1;i<=n;i++)
ans[tot][i]=a[i];
}
int main(){
n=read();
m=n*(n-1)/2;
for(int i=1;i<=m;i++)
c[i]=read();
sort(c+1,c+m+1);
for(int i=3;i<=m;i++)
if(c[i]!=c[i-1])solve(i);
print(tot);
putchar('\n');
for(int i=1;i<=tot;i++)
{
for(int j=1;j<=n;j++)
{
print(ans[i][j]);
if(j!=n)putchar(' ');
}
if(i!=tot)putchar('\n');
}
return 0;
}
二分+vector
vector数组f[v]保存了所有灯的数量为v的位置
灯数模p等于v的有:v,v+p,v+2p…
每次二分查找f[v]中位置范围在[l,r]内的最左和最右的位置,并统计答案。然后v+=p,继续统计,直到v超过了1e4的范围。
#include<bits/stdc++.h>
using namespace std;
const int N=100005,inf=0x3f3f3f3f;
int n,m,l,r,p,v,sum,lt,rt;
int a[N],ansl,ansr;
vector<int>f[10001];
int read(){
int sum=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return sum*f;
}
void print(int x)
{
if(x<0)x=-x,putchar('-');
if(x>9)print(x/10);
putchar(x%10+'0');
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++)
{
a[i]=read();
f[a[i]].push_back(i);
}
while(m--)
{
lt=read();rt=read();p=read();v=read();
sum=0;
while(v<=10000)
{
int l=0,r=f[v].size()-1,ansl=-1,ansr=-1;
while(l<=r)
{
int mid=(l+r)>>1;
if(f[v][mid]>=lt)ansl=mid,r=mid-1;
else l=mid+1;
}
if(ansl==-1){v+=p;continue;}
l=0,r=f[v].size()-1;
while(l<=r)
{
int mid=(l+r)>>1;
if(f[v][mid]<=rt)l=mid+1,ansr=mid;
else r=mid-1;
}
if(ansr==-1){v+=p;continue;}
sum+=ansr-ansl+1;
v+=p;
}
print(sum);
if(m!=0)putchar('\n');
}
return 0;
}