10.12 csp-s模拟测试70 木板+打扫卫生+骆驼

T1 木板

求$[\sqrt{n},n)$间有多少个数的平方是n的倍数

通过打表可以发现(我没带脑子我看不出来),符合条件的数构成一个等差数列,公差为首项

而首项就是将n质因数分解后每个质因数出现次数除二,向上取整,这个数一定是大于$\sqrt{n}$的最小的符合条件的数

$\sqrt{n}$将$n$分解质因数后求出首项,$(n-1)/$首项就是小于$n$里有几个,即答案

积累:$papa$大神教我,打表之前先猜规律,用小点看看猜的对不对,然后再用大点验证,想不出来的数学题就打打表,找找规律

 

#include
#include
#include
#define ll long long
using namespace std;
ll n,ans,z[100100],cnt,num[100100];
ll read()
{
    ll aa=0,bb=1;char cc=getchar();
    while(cc>'9'||cc<'0'){if(cc=='-') bb=-1;cc=getchar();}
    while(cc<='9'&&cc>='0'){aa=(aa<<3)+(aa<<1)+(cc^'0');cc=getchar();}
    return aa*bb;
}
void devide(ll x)
{
    ll xx=sqrt(x);
    for(ll i=2;i<=xx;i++){
        if(x%i==0){
            z[++cnt]=i;num[cnt]=0;
            while(x%i==0) x/=i,num[cnt]++;
        }
    }
    if(x>1) z[++cnt]=x,num[cnt]=1;
}
ll quick(ll x,ll p)
{
    ll as=1;
    while(p){
        if(p&1) as=as*x;
        x=x*x;
        p>>=1;
    }
    return as;
}
int main()
{
    while(1){
        n=read();ans=1;cnt=0;
        if(!n) break;
        devide(n);
        for(ll i=1;i<=cnt;i++) ans*=quick(z[i],(num[i]+1)/2);
        printf("%lld\n",(n-1)/ans*8);
    }
    return 0;
}
木板

 

T2 打扫卫生

首先肯定是$dp$

考场写的是$n^2$的,每次用桶把$a[j]$的贡献减去,更新答案,最后再循环一遍都加回来,$T60$

但我们发现如果不同的数的个数大于了$\sqrt{n}$,那么他一定不优(大于$\sqrt{n}$,那还不如一段就一个,这样就只有$n$)

所以我们可以在往回加的时候特判,如果$cnt$大于$\sqrt{n}$,那就记录下这个位置,然后$break$,下次循环就只从$pos$循环就行了,加上这个减枝可以到$T80$

正解:$cnt$一定小于$\sqrt{n}$,那么我们枚举i前不同的数的个数,复杂度就降到了$O(n\sqrt{n})$

用$pre[a[i]]$记录$a[i]$上次出现的位置,$b[j]$表示从$b[j]+1~i$一共有$j$个不同的数,$c[j]$表示从$b[j]+1~i$有多少个不同的数

$i++$后,如果$pre[a[i]]<=j$,说明$a[i]$在$b[j]+1~i-1$这一段没有出现过,所以$b[j]+1~i$这一段中不同数的个数就变成了$c[j]+1$,更新$c[j]$

如果$c[j]>j$,我们为了维护$c[j]==j$,就需要调整$b[j]$的位置,使$b[j]$合法

设$pos=b[j]+1$(原位置),如果$pre[a[pos]]>pos$说明在后面还有一个$a[pos]$,那么删掉这个对个数没有影响,直到$pre[a[pos]]<=pos$,那么删掉这个数,$pos+1~i$这个区间就正好有$j$个数了,更新$b[j]=pos$,$c[j]=j$,同时更新$f[i]$数组

积累:没有思路想$dp$,优化的时候找$dp$的瓶颈,看是否能用一些数据结构或多记一些东西突破他

 

#include
#include
#include
#include
using namespace std;
int n,m,nn,a[40010],b[40010],c[40010],pre[40010],f[40010];
int read()
{
    int aa=0,bb=1;char cc=getchar();
    while(cc>'9'||cc<'0'){if(cc=='-') bb=-1;cc=getchar();}
    while(cc>='0'&&cc<='9'){aa=(aa<<3)+(aa<<1)+(cc^'0');cc=getchar();}
    return aa*bb;
}
int main()
{
    n=read();m=read();nn=sqrt(n);
    for(int i=1;i<=n;i++) a[i]=read();
    memset(pre,-1,sizeof(pre));
    for(int i=1;i<=n;i++){
        f[i]=f[i-1]+1;
        for(int j=1;j<=nn;j++)
            if(pre[a[i]]<=b[j]) c[j]++;
        pre[a[i]]=i;
        for(int j=1;j<=nn;j++){
            if(c[j]>j){
                int pos=b[j]+1;
                while(pre[a[pos]]>pos) pos++;
                b[j]=pos;c[j]--;
            }
            f[i]=min(f[i],f[b[j]]+j*j);
        }
    }
    printf("%d\n",f[n]);
    return 0;
}
打扫卫生

 

T3 骆驼

咕咕咕

你可能感兴趣的:(10.12 csp-s模拟测试70 木板+打扫卫生+骆驼)