2013多校联合1部分题解(更新中)

今天先水两发

hdu 4602

这道题仅从表面上看没啥头绪,后来仔细分析2^(n-1)的原因,就明白了,那么2^(n-1)个方法是怎样来的,首先对于n=k来讲,可以由任意n=k-1组成的序列前面+1,由任意n=k-2组成的序列前面+2。。。以此类推,方法估计2^(n-2)+2^(n-3)+..+1 + 1 =2^(n-1),这样也就知道f(n,k)怎样处理了。假设k=1时,f(n,k)=g(n) = 2*g(n-1) + 2^(n-3)。。(推导过程省略,前面的都明白的话不用写了这里)...而f(n,k) = g(n-k+1) 也易证,ok

#include <iostream>
#include <cstdio>

#define ss(a) scanf("%d",&a)
#define cl(a) memset(a,0,sizeof(a))
#define mod 1000000007
#define N 40
#define ll __int64

using namespace std;

ll a[N][3][3],r[3];

void init()
{
    int i,j;
    cl(a);cl(r);
    a[0][1][1]=2;a[0][1][2]=1;
    a[0][2][1]=0;a[0][2][2]=2;
    r[1]=2;r[2]=1;    
}

void zmul(int x)
{
    ll y1,y2;
    y1=(a[x][1][1]*r[1]%mod+a[x][1][2]*r[2]%mod)%mod;
    y2=(a[x][2][1]*r[1]%mod+a[x][2][2]*r[2]%mod)%mod;
    r[1]=y1;
    r[2]=y2;
}

void rmul(int x)
{
    int i,j,k;
    for (i=1;i<=2;i++)
        for (j=1;j<=2;j++)
        {
            a[x][i][j]=0;
            for (k=1;k<=2;k++) a[x][i][j]=(a[x][i][j]+a[x-1][i][k]*a[x-1][k][j]%mod)%mod;
        }
}

void fast(int t)
{
    int i=0;
    while (t>0)
    {
        if (t&1) zmul(i);
        i++;
        rmul(i);
        t>>=1;
    }
}

void quick(int t)
{
    init();
    fast(t);
    cout<<r[1]<<endl;
}

int main()
{
    int n,k,T;
    ss(T);
    while (ss(n)!=EOF)
    {
        ss(k);
        if (k>n) 
        {
            cout<<0<<endl;
            continue;
        }
        int t=n-k+1;
        if (t<=1)
        {
            cout<<1<<endl;
            continue;
        }        
        quick(t-2);
    }
    return 0;
}

hdu 4608 没啥好说的,模拟就是了,因为没看见y>x WA了一次(以为Y>=X。。。。)

#include <iostream>
#include <cstdio>
#include <string>

#define N 100004
#define cl(a) memset(a,0,sizeof(a))

using namespace std;

int s[N];

int main()
{
    int T,i;
    string ss;
    cin>>T;
    while (T--)
    {
        cin>>ss;
        int l=ss.length(),d=0;
        for (i=0;i<l;i++)
            d=(d+(ss[i]-'0'))%10;
        int x=9-(ss[l-1]-'0');
        if ((d+x)>=10)
        {
            ss[l-1]+=(10-d%10);
            cout<<ss<<endl;
        }
        else
        {
            cl(s);
            int d=0,r;
            for (i=1;i<l;i++) s[i]=ss[i-1]-'0';
            s[l]=0;
            i=l-1;
            r=(s[i]+1)/10;
            s[i]=(s[i]+1)%10;
            while (r>0)
            {
                i--;
                int x=s[i]+r;
                r=x/10;
                s[i]=x%10;
            }    
            for (i=0;i<l;i++) d=(d+s[i])%10;
            if (!d) s[l]=0;
            else s[l]=10-d;
            if (s[0]) cout<<s[0];
            for (i=1;i<=l;i++) cout<<s[i];
            cout<<endl; 
        }
    }
    return 0;
}


HDU 4610

坑爹啊,细节太多了。。。各种错误,先是WA,后来找到错误,不知道怎么解决,看了爱神博客,然后继续WA+TLE了好几次,花了差不多2个下午的时间有木有。。。

首先是第一问,四个条件,要首先熟悉数论得到求约数和求约数和的公式,这里不多说,我的博客往前翻应该是有的~

第4个条件,判断约数的乘积是否为完全平方数,非完全平方数n的每一对约数的乘积都是n,所以看它的约数个数是否能整除4即可,对于完全平方数,如果它的开方仍是完全平方数,则它一定符合要求,否则要看它的约数个数是否为偶数

关键是第2问,真的没有想到枚举2^16算法,然而枚举的时候也有很多坑,比如某个枚举方案是否可行要想想,在贪心的情况下怎能确保你的枚举方案是针对这一种状态而不是其它状态?附代码吧。。。。

这道题非常推荐,自己的确太弱弱弱了。。。。。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>

#define N 1000005
#define M 1004
#define ss(a) scanf("%d",&a)
#define cl(a) memset(a,0,sizeof(a))
#define pb push_back
#define MINUM -200000

using namespace std;

int a[N],cnt[N],score[N];
int data[M],extra[5],w[17],v[17],b[5];
vector<int>pri;

void prime()
{
    int i,j;
    for (i=2;i<N;i++)
        if (!a[i])
        {
            pri.pb(i);
            for (j=2*i;j<N;j+=i) 
                if (!a[j]) a[j]=i; 
        }
}

int pd(int x,int n)
{
    int i,res;
    res=(n*x-1)/(x-1);
    for (i=0;i<pri.size()&&pri[i]*pri[i]<=res;i++)
    {
        if (res%pri[i]==0) return 0;
    } 
    return 1;
}

void init()
{
    prime();
    int i;
    score[1]=8;
    cnt[1]=1;
    for (i=2;i<N;i++)
        if (!a[i]) 
        {
            if (i==2) score[i]=7;
            else score[i]=3;
            cnt[i]=2;
        }
        else
        {
            int t=0,x=i;
            while (x%a[i]==0) 
            {
                x/=a[i];
                t++;
            }
            cnt[i]=cnt[i/a[i]]/t*(t+1); 
            if (!a[cnt[i]]) score[i]+=2;
            if (x==1)
            {
                if (pd(a[i],i)) score[i]+=4;
            } 
            int i0=sqrt(i);
            if (i0*i0!=i)
            {
                if (cnt[i]%4==0) score[i]+=8;
            } 
            else 
            {
                int r=sqrt(i0);
                if (r*r==i0) score[i]+=8;
                else if (cnt[i]%2==0) score[i]+=8; 
            }
        }
    return;
}

int js(int x)
{
    int i,sc=0;
    for (i=0;i<4;i++)
        if (x&(1<<i)) sc++;
    return sc; 
}

int main()
{
    int T,i,j,n,k;
    ss(T);
    init();
    for (i=0;i<16;i++) v[i]=js(i);
    while (T--)
    {      
        ss(n);ss(k);
        cl(w);
        for (i=1;i<=n;i++)  
        {
            int value,num;
            ss(value);ss(num);
            int x=score[value];
            w[x]+=num;
            data[i]=v[x];
        }   
        for (i=0;i<4;i++) ss(extra[i]);
        for (i=1;i<n;i++) printf("%d ",data[i]);
        printf("%d\n",data[n]); 
        int res=MINUM;
        for (i=0;i<(1<<16);i++)
        {
            int u=0,re=0,extr=0,u0=0;
            cl(b);
            for (j=0;j<16;j++) 
                if (i&(1<<j))
                {
                    if (w[j]==0) 
                    {
                        u0=-1;
                        break;
                    }                     
                    u++;
                    u0+=w[j];
                    re+=v[j];
                    extr=(extr|j);
                    b[v[j]]+=(w[j]-1);
                }                    
            if (u>k) continue;
            if (u0<k) continue;
            for (j=0;j<4;j++)
                if (!(extr&(1<<j))) re+=extra[j];
            for (j=3;j>=1;j--)
                if (u+b[j]<=k)
                {
                    u+=b[j];
                    re+=b[j]*j;
                }
                else
                {
                    re+=(k-u)*j;
                    break;
                }
            res=max(res,re);  
        }                    
        printf("%d\n",res);
    }
    return 0;
}


hdu 4604 Deque

这道题其实就是就是转换成一个数学模型·,官方题解写的很清楚,就是枚举队列第一个量x,长度为以该数为起点的最长单调不降子序列长度+最长单调不升序列长度-重复部分,重复部分为两个序列含x的最小值(这个也是一个关键的细节),接下来瞎整了很长时间,线段树超时,然后学了一下O(NLOGN)的二分解法,AC,弱死。。。

这道题还是很不错的题,是考验思维能力的好题

#include <iostream>
#include <cstdio>

#define N 100005
#define ss(a) scanf("%d",&a)
#define cl(a) memset(a,0,sizeof(a))

using namespace std;

int a[N],g[N],f[N],b[N],upcon[N],downcon[N];

int biny(int x,int l,int r)
{
    if (r-l<=1)
    {
        if (x==b[l]) return l;
        else return r;
    }
    int m=(l+r)>>1;
    if (x<=b[m]) return biny(x,l,m);
    else return biny(x,m+1,r); 
}

int up_biny(int x,int l,int r)
{
    if (r-l<=1)
    {
        if (x<=f[r]) return r;
        else if (x<=f[l]) return l;
        else return l-1;
    }
    int m=(l+r)>>1;
    if (x<=f[m]) return up_biny(x,m,r);
    else return up_biny(x,l,m-1);  
}


int down_biny(int x,int l,int r)
{
    if (r-l<=1)
    {
        if (x>=g[r]) return r;
        else if (x>=g[l]) return l;
        else return l-1;
    }
    int m=(l+r)>>1;
    if (x>=g[m]) return down_biny(x,m,r);
    else return down_biny(x,l,m-1);  
}


int main()
{
    int T,n,i;
    ss(T);
    while (T--)
    {
        ss(n);
        for (i=1;i<=n;i++) 
        {
            ss(a[i]);
            b[i]=a[i];
            g[i]=2*n;
            f[i]=-1;
        }
        sort(b+1,b+n+1);
        for (i=1;i<=n;i++) a[i]=biny(a[i],1,n);
        cl(upcon);cl(downcon);
        g[1]=f[1]=a[n];
        upcon[a[n]]=downcon[a[n]]=1;
        int res=1;
        for (i=n-1;i>=1;i--)
        {
            int x,y,w=a[i];
            x=up_biny(w,1,n);
            if (w==f[x]) upcon[w]++;
            else upcon[a[i]]=1;
            f[++x]=max(f[x],w);
            y=down_biny(w,1,n); 
            if (w==g[y]) downcon[w]++;
            else downcon[w]=1;
            g[++y]=min(g[y],w);
            res=max(res,x+y-min(upcon[w],downcon[w]));      
        }
        cout<<res<<endl;
    }
    return 0;   
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值