p1802,p1806,p1808

  新高一第二期培训开始了,虽然不是我的班也来快乐了.早上来的时候见到了新高一去军训的场面,还挺感动的.

  然后上午并没人问我,我就在校oj刷题,一上午整了三道,美滋滋.

  

 

 

   p1802一看就是一个动态规划.考虑每个树能取的状态和前一个树相关,而且不止与前一个树高度相关,还和前前一个树相关.所以我设了四个状态表示当前树的高度和与前一个树的关系.分别是:最低,中等且前一个树更高,中等且前一个树更低,最高.

 

 

   这样就可以开始转移了,但是如果给f[1]的四个状态都赋值就会使得最后的答案不明确,因为成环的原因嘛.那么可以考虑关于一树的状态再分状态.f[i][j][k]表示1树状态为j,树i状态为k时的最大观赏值.转移也很好转移,答案是f[n][1..4][1..4]中的最大值.但是我懒省事就复制粘贴了四个.

long long a[100010][5],f[100010][5];
long long maxx(long long a,long long b,long long c)
{
    a=a>b?a:b;
    return a>c?a:c;
}
int main()
{
    int n=read();
    for(int i=1;i<=n;i++)
    {
        a[i][1]=read();
        a[i][2]=read();
        a[i][3]=read();
    }    
    //1:
    f[1][1]=a[1][1];
    f[1][2]=f[1][3]=f[1][4]=-10000000;
    for(int i=2;i<=n;i++)
    {
        f[i][1]=a[i][1]+max(f[i-1][4],f[i-1][3]);
        f[i][2]=a[i][2]+f[i-1][4];
        f[i][3]=a[i][2]+f[i-1][1];
        f[i][4]=a[i][3]+max(f[i-1][1],f[i-1][2]);
    }
    long long ans;
    ans=max(f[n][3],f[n][4]);
    //2
    f[1][2]=a[1][2];
    f[1][1]=f[1][3]=f[1][4]=-10000000;
    
    for(int i=2;i<=n;i++)
    {
        f[i][1]=a[i][1]+max(f[i-1][4],f[i-1][3]);
        f[i][2]=a[i][2]+f[i-1][4];
        f[i][3]=a[i][2]+f[i-1][1];
        f[i][4]=a[i][3]+max(f[i-1][1],f[i-1][2]);
    }
    ans=max(ans,f[n][4]);
    //3
    f[1][3]=a[1][2];
    f[1][1]=f[1][2]=f[1][4]=-10000000;
    for(int i=2;i<=n;i++)
    {
        f[i][1]=a[i][1]+max(f[i-1][4],f[i-1][3]);
        f[i][2]=a[i][2]+f[i-1][4];
        f[i][3]=a[i][2]+f[i-1][1];
        f[i][4]=a[i][3]+max(f[i-1][1],f[i-1][2]);
    }
    ans=max(ans,f[n][1]);
    //4
    f[1][4]=a[1][3];
    f[1][1]=f[1][2]=f[1][3]=-10000000;    
    for(int i=2;i<=n;i++)
    {
        f[i][1]=a[i][1]+max(f[i-1][4],f[i-1][3]);
        f[i][2]=a[i][2]+f[i-1][4];
        f[i][3]=a[i][2]+f[i-1][1];
        f[i][4]=a[i][3]+max(f[i-1][1],f[i-1][2]);
    }
    ans=maxx(ans,f[n][1],f[n][2]);
    cout<<ans;
    return 0;
}
p1802

  p1806读懂了题意后考虑不写程序的话普通人会怎么做.应该先看最后一位能不能++,如果能就++走人,否则看倒数第二位能不能++,并且使得倒数第一位为倒数第二位原来的字母+2.如果能就这样做,以此类推.

  那么对于第i位只需判断是否w-i<t-ans[i].如果可以就枚举后面所有位,使得ans[j]=ans[j-1]+1;.

char s,t;
int w;
char ans[30];
void work()
{
    for(int i=w;i;i--)
        if(ans[i]<t&&w-i<t-ans[i])
        {
            ans[i]=ans[i]+1;    
            for(int j=i+1;j<=w;j++)
                ans[j]=ans[j-1]+1;
            return ;
        }
    exit(0);
}
int main()
{
    s=read()+'a'-1;t=read()+'a'-1;w=read();
    for(int i=1;i<=w;i++)
        cin>>ans[i];
    for(int i=1;i<=5;i++)
    {
        work();
        for(int j=1;j<=w;j++)
            cout<<ans[j];
        cout<<endl;
    }
    return 0; 
}
p1804

  p1808答案就是c(m+n,m)的后一百位.我会高精度!但是除法不太行,因为求不了逆元.

  考虑在班里求组合数,先把分子分母写出来,然后上下消去公因数,然后再把分子乘起来的操作.类比一下,先求出1到m+n的质数并且存起来,对于需要求的组合数,只需要记录m+1到m+n和2到n的数的质因数还剩下多少,再用高精度乘起来.高精度乘单精度还是很好写的.

  这道是我上午写的最简单的题了.

long long num[100000],sum[100010],k;
long long ans[30];
bool zhi(int x)
{
    for(int i=sqrt(x*1.0);i>=2;i--)
        if(x%i==0)
            return 0;
    return 1;
}
void Add(long long  x)
{
    for(int i=1;x>=num[i]&&i<=k;i++)
    {
        while(x%num[i]==0)
            x=x/num[i],sum[i]++;
    }
    return ;
}
void Minus(long long x)
{
    for(int i=1;x>=num[i]&&i<=k;i++)
    {
        while(x%num[i]==0)
            x=x/num[i],sum[i]--;
    }
    return ;
}
void mul(long long x)
{
    for(int i=1;i<=20;i++)
        ans[i]=ans[i]*x;
    for(int i=1;i<=20;i++)
        ans[i+1]+=ans[i]/100000,ans[i]=ans[i]%100000;
    return ;
}
int main()
{
    int m=read(),n=read();
    if(m<n)
        swap(m,n);
    for(int i=2;i<=m+n;i++)
        if(zhi(i))
            k++,num[k]=i;
    for(int i=m+n;i>m;i--)
        Add(i);
    for(int i=2;i<=n;i++)
        Minus(i); 
    ans[1]=1;
    for(int i=1;i<=k;i++)
        while(sum[i])
            mul(num[i]),sum[i]--;
    for(int i=20;i;i--)
    {
        long long t=10000;
        while(t&&ans[i]/t==0)
            cout<<0,t=t/10;
        if(ans[i])
            cout<<ans[i];
        if(i%2)
            cout<<endl;
    }
    return 0;
}
p1806

 

  然后中午学弟问了我一道统计数字:

某次科研调查时得到了n(n<=200000)个自然数,每个数均不超过1500000000(1.5*10^9)。已知不相同的数不超过10000个,现在需要统计这些自然数各自出现的次数,并按照自然数从小到大的顺序输出统计结果。

  他们还没学sort,桶排序也不行,这可咋办呢?

  我一拍大腿,我会map!

  作为map的忠实粉丝,即使map常数很大,但因为它的简单易行(与数组相似),我一直很喜欢用它艹一些题.

  map<long long,int>sum;来统计每个数的数量.然后用一个迭代器便利map里的元素输出即可.

map<long long,int> a;
long long n,x,maxx;
int main()
{
    n=read();
    while(n)
        a[read()]++,n--;
    map<long long,int>::reverse_iterator   iter;
    for(iter = a.rend(),iter--; iter != a.rbegin(); iter--)
    {
        write(iter->first);
        putchar(32);
        write(iter->second);
        putchar(10);
    } 
    write(iter->first);
    putchar(32);
    write(iter->second);     
    return 0;
} 
#92统计数字

  最后用map艹翻了一众sort,.

 

   

 

posted @ 2020-08-17 13:19  zzuqy  阅读(206)  评论(0编辑  收藏  举报