lxs Contest #120 2020.1.19

t2

前50分很好搞。

对于后50分,先询问8次,每次询问形如{1,\(10^{49}\)} ,这样我们就得到了8个 数的后头49位,我们只要求出了另一个数的后8位即可求出这8个数及另一个数。

所以在询问两次{0,1,0,\(10^{8}\),0,\(10^{16})\,……}。即可得出这些数的后8位。

要手写高精度减法,码量大,莫得代码。

t3 走路

【题意】

有n个地点,x点行动力,起点为0,餐馆地点为1-n,到一个餐馆可以选择吃a[i]点食物,在吃了k点食物后每走一步就需要(k+1)的行动力,求在可以回到起点的情况下最多可以吃好多点食物。

对于30%

实际上每个地方如果选了则代价就是i*a[i],贡献是a[i]。就可以直接跑01背包。

对于100%

考虑设f[i][j]表示只选择后头i--n个餐馆,吃了j个食物所需要的最小代价。转移方程很简单\(f[i][j]=min(f[i+1][j],f[i+1][j-a[i]]+a[i]*i)\),特别的,f[i][a[i]]可以从和2*i+i*a[i]取min。

分析复杂度,因为从i带着j的食物回到0所需最小代价为i*j所以j只需枚举到x/i即可,复杂度为O(nlogm)。

代码如下:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
int n,k,a[N],f[2][N*10],l,r,ans;//f[i][j]表示在i-n这些餐馆中吃了j坨食物所花最小代价。 
inline int read()
{
    char c=getchar();
    int x=0,f=1;
    while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
    while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return x*f;
}
signed main()
{
    //freopen("w.in","r",stdin);
    //freopen("w.out","w",stdout);
    n=read();k=read();
    for(int i=1;i<=n;i++) a[i]=read();
    memset(f,0x3f3f3f3f,sizeof(f));
    for(int i=n;i>=1;i--)
    {
        
        for(int j=0;j<=k/i;j++)
        {
            f[i%2][j]=f[(i+1)%2][j];
            if(j>=a[i]) 
                f[i%2][j]=min(f[(i+1)%2][j],f[(i+1)%2][j-a[i]]+i*a[i]);
            if(f[i%2][j]<=k) ans=max(ans,j);
        }
        f[i%2][a[i]]=min(f[i%2][a[i]],i+i+a[i]*i);
        if(i+i+a[i]*i<=k) ans=max(ans,a[i]);
    }
    cout<<ans;
//    fclose(stdin);
//    fclose(stdout); 
    return 0;
}
/*
5 10
1 1 1 1 1
*/
View Code
posted @ 2020-01-19 23:22  精海臭脚  阅读(189)  评论(0编辑  收藏  举报