其他分享
首页 > 其他分享> > 【2019.10.25】

【2019.10.25】

作者:互联网

summary

小奇采药

对于 30% 的数据,O(2n ) 枚举取 or 不取

对于 60% 的数据,O(nm) 做 01 背包,即 f(i, j) 表示前 i 株 草药,耗费 j 的时间能达到的最⼤代价。

对于 100% 的数据,注意到 m,t,v 纯随机

那么不会选太多的草药,⽽耗时较少的草药有很⼤概率存在 于最优解中

针对这些性质优化搜索

当然也可以合理使用随机化和卡时,复杂度 O(⽞学)

最基础60昏的背包

dfs写错了... 幸好我分开搞得 不然就爆炸

struct node{int co,val;}a[N];
bool cmp(node x,node y){return x.co>y.co;}

ll f[100010],ans,sumc[N],sumv[N];
void work(){//60昏 
    memset(f,0,sizeof(f));
    for(int i=1;i<=n;++i)
    for(int j=m;j>=a[i].co;--j)
    f[j]=max(f[j],f[j-a[i].co]+a[i].val);
    printf("%lld\n",f[m]);
}

bool vis[N];
void dfs(int pos,ll co,ll val){
    ans=Max(ans,val);
    if(pos>n) return;
    if(co+a[n].co>m) return;
    if(val+sumv[pos]<=ans) return;
    if(co+sumc[pos]<=m){ans=Max(val+sumv[pos],ans);return;}
    if(co+a[pos].co<=m) dfs(pos+1,co+a[pos].co,val+a[pos].val);
    dfs(pos+1,co,val);
}
void work2(){
    ans=0;dfs(1,0,0);
    printf("%lld\n",ans);
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
#endif
    int T;rd(T);
    while(T--){
        rd(n),rd(m),sumv[n+1]=sumc[n+1]=0;
        for(int i=1;i<=n;++i) rd(a[i].co),rd(a[i].val);
        sort(a+1,a+n+1,cmp);
        for(int i=n;i;--i) sumv[i]=sumv[i+1]+a[i].val,sumc[i]=sumc[i+1]+a[i].co;
        //if(m<=100000) work();
        work2();
    }
    return 0;
}

小奇的数列2

第一反应 双指针?!

很容易发现 若一个区间为可约的 那么这个区间的gcd一定等于其最小值

然后发现可以二分 就开始打线段树来维护 打完后发现二分的过程中有很多此询问 gcd和最小值都可以用st表来维护 然后\(O(1)\)询问最合适了!

然后这就是正解辽?!

int gcd(int x,int y){return !y?x:gcd(y,x%y);}
int gc,mn;
void query(int x,int y){
    int s=lg[y-x+1];
    gc=gcd(Gc[x][s],Gc[y-(1<<s)+1][s]),mn=Min(Mn[x][s],Mn[y-(1<<s)+1][s]);
}
bool check(int mid){
    for(int l=1;l+mid<=n;++l)
    if(query(l,l+mid),gc==mn) return 1;
    return 0;
}
int main(){
    //freopen("sequence.in","r",stdin);
//  freopen("sequence.out","w",stdout);
    rd(n);
    for(int i=1;i<=n;++i) rd(a[i]);
    cm[0]=1,lg[0]=-1;for(int i=1;i<20;++i) cm[i]=cm[i-1]<<1;
    for(int i=1;i<=n;++i) Gc[i][0]=Mn[i][0]=a[i],lg[i]=lg[i>>1]+1;Mn[n+1][0]=0;
    for(int j=1;j<20;++j)
        for(int i=1;i+cm[j]-1<=n+1;++i){
            Gc[i][j]=((Gc[i][j-1]==1||Gc[i+cm[j-1]][j-1]==1)?1:gcd(Gc[i][j-1],Gc[i+cm[j-1]][j-1])),
            Mn[i][j]=Min(Mn[i][j-1],Mn[i+cm[j-1]][j-1]);
        }
    int l=0,r=n-1,mid,ans,cnt=0;
    while(l<=r){
        int mid=l+r>>1;
        if(check(mid)) l=mid+1,ans=mid;
        else r=mid-1;
    }
    if(!ans){
        printf("%d %d\n",n,0);
        for(int i=1;i<=n;++i) printf("%d ",i);
    }
    else{
        for(int i=1;i+ans<=n;++i)
            if(query(i,i+ans),gc==mn) b[++cnt]=i;
        printf("%d %d\n",cnt,ans);
        for(int i=1;i<=cnt;++i)  printf("%d ",b[i]);
    }
    return 0;
}

小奇学数论

我... 表打炸了...

对于 20% 的数据,枚举 1 到 n,暴⼒判断素数。

对于 40% 的数据,枚举 1 到 n,判断素数的时候只需要循 环 1 − √ n

对于 60% 的数据,筛法

对于 80% 的数据,容斥原理

对于 100% 的数据,分段 + 前缀和打表 还有个⿊科技 Meissel-Lehmer 算法

分块打表 打表时用的是做素数密度那道题的方法==

int cnt=0,prime[700000];bool v[N];
void primes(){
    for(ll i=2;i<=n;++i){
        if(!v[i]) v[i]=1,prime[++cnt]=i;
        for(int j=1;j<=cnt&&i*prime[j]<=n;++j){
            v[i*prime[j]]=1;
            if(!(i%prime[j])) break;
        }
    }
}

bool a[5000010];
void work(){
    m=n,n=1000000ll;primes();
    for(int i=1;i<=m/5000000;++i) ans+=table[i];
    ll L=(m/5000000ll+1)*5000000ll,R=m;
    if(!(m%5000000ll)) {printf("%lld\n",ans);return;}
    memset(a, 0, sizeof(a));
    for (int i=1;i<=cnt;++i)
        for(ll j=max(2ll,(L-1)/prime[i]+1)*prime[i];j<=R;j+=prime[i]) a[j-L]=1;
    for(ll i=L;i<=R;++i)
        if(!a[i - L]) ++ans;
    printf("%lld",ans);
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
#endif
    rd(n);
    if(n<=10000000){
        primes();
        printf("%d",cnt);
    }
    else work();
/*  int i=1;
    for(;i<=20000;++i) if(table[i]==2) break;
    printf("%d",i);*/
    return 0;
}

标签:25,co,gcd,val,int,ll,2019.10,ans
来源: https://www.cnblogs.com/lxyyyy/p/11738487.html