码迷,mamicode.com
首页 > 其他好文 > 详细

10.1 考试 ..........

时间:2017-10-01 16:19:05      阅读:244      评论:0      收藏:0      [点我收藏+]

标签:欧拉图   line   namespace   opera   滚动   amp   play   否则   clear   

T1 网格

显然 n==m时,卡特兰数

n,m<=100时,滚动数组的dp

正解

ans=C(n+m,n)-C(n+m,n+1)

不会证,但是可以类比 cantelan数公式 C(2*n,n)-C(2*n,n-1)

 

技术分享
#pragma GCC optimize("O2")
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
const int N=5006;
const int LEN=20006;

struct bign
{
    int s[LEN],len;
    bign(){mem(s,0);len=1;}
    void clear(){mem(s,0);len=1;}
    bign operator * (const int c)
    {
        bign t=*this;
        int jin=0;
        for(int i=1;i<=t.len;++i)
        {
            t.s[i]=(t.s[i]*c+jin);
            jin=t.s[i]/10;
            t.s[i]%=10;
        }
        t.s[t.len+1]=jin;
        ++t.len;
        while(t.s[t.len]==0&&t.len>1)
            --t.len;
        while(t.s[t.len]>=10)
        {
            t.s[t.len+1]=t.s[t.len]/10;
            t.s[t.len]%=10;
            ++t.len;
        }
        return t;
    }
    bign operator / (const int c)
    {
        bign t=*this;
        for(int i=t.len;i>=1;--i)
        {
            t.s[i-1]+=t.s[i]%c*10;
            t.s[i]/=c;
        }
        while(t.s[t.len]==0&&t.len>1)
            --t.len;
        return t;
    }
    bign operator + (bign &c)
    {
        bign now=*this;
        //printf("yuan\n");
        //now.out1();
        //c.out1();
        now.len=max(c.len,now.len)+1;
        for(int i=1;i<=now.len;++i)
        {
            now.s[i+1]+=(now.s[i]+c.s[i])/10;
            now.s[i]=(now.s[i]+c.s[i])%10;
        }
        while(now.s[now.len]==0&&now.len>1)
            --now.len;
        //now.out1();
        return now;
    }
    bign operator - (bign &c)
    {
        bign now=*this;
        for(int i=1;i<=now.len;++i)
        {
            if(now.s[i]<c.s[i])
            {
                --now.s[i+1];
                now.s[i]+=10;
            }
            now.s[i]-=c.s[i];
        }
        while(now.s[now.len]==0&&now.len>1)
            --now.len;
        return now;
    }
    void out1()
    {
        for(int i=len;i>=1;--i)
            printf("%d",s[i]);
        //printf("\n");
    }
};

int n,m;
bign a,b,c;

// C(n+m,n)-C(n+m,n+1)
int main(){

    scanf("%d%d",&n,&m);

    a.s[1]=1;b.s[1]=1;
    for(int i=1;i<=n;i+=2)
        a=a*( (n+m-i+1) * (i+1>n?1:n+m-i) );
    for(int i=1;i<=n;i+=2)
        a=a/(i*(i+1>n?1:i+1));
    for(int i=1;i<=n+1;i+=2)
        b=b*( (n+m-i+1) * (i+1>n+1?1:n+m-i) );
    for(int i=1;i<=n+1;i+=2)
        b=b/(i*(i+1>n+1?1:i+1));

    //a.out1();
  //b.out1();
    c=a-b;
    c.out1();

}
T1

 

T2

把两个操作分开考虑,先熔断,在连接

1.对于只有一个联通快

(1)是环 ans=0

(2)是欧拉图 ans=(deg大于2的点)

(3)否则 (deg大于2的点)+(deg奇数点/2)

2.对于多个

(1)是环,直接熔断ans+1,liansum+1

(2)是欧拉图,在熔断deg>2点同时熔断成链,ans+(deg>2_sum),lainsum+1

(3)否则 ans+(deg>2_sum) liansum+(奇数点/2)

finaans=ans+liansum

 

技术分享
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=500006;
struct son
{
    int v,next;
}a1[N*2];
int first[N*2],e;
void addbian(int u,int v)
{
    a1[e].v=v;
    a1[e].next=first[u];
    first[u]=e++;
}

int n,m;
int deg[N];
int l0[N],r0[N];

bool vis[N];
int tot,cc;
void dfs1(int x)
{
    vis[x]=1;
    ++cc;
    int temp;
    for(int i=first[x];i!=-1;i=a1[i].next)
    {
        temp=a1[i].v;
        if(vis[temp])
            continue;
        dfs1(temp);
    }
}

int work1()// 鍙湁涓€涓仈閫氬潡
{
    //printf("work1\n");
    int cntji=0,cntou=0,cntda=0;
    for(int i=1;i<=n;++i)
    {
        if(deg[i]&1)
            ++cntji;
        else
            ++cntou;
        if(deg[i]>2)
            ++cntda;
    }
    if(cntji==0)// 鏄鎷夊洖璺? OR 鐜?
        return cntda;
    return cntda+cntji/2;// 鍏堢啍鏂垚閾撅紝鍦ㄦ帴璧锋潵
}

int sum,cntji,cntou,cntda;
void dfs(int x)
{
    vis[x]=1;
    ++sum;
    if(deg[x]&1)
        ++cntji;
    else
        ++cntou;
    if(deg[x]>2)
        ++cntda;
    int temp;
    for(int i=first[x];i!=-1;i=a1[i].next)
    {
        temp=a1[i].v;
        if(vis[temp])
            continue;
        dfs(temp);
    }
}

int work2()
{
    printf("work2\n");
    mem(vis,0);
    int liansum=0,ans=0;
    for(int i=1;i<=m;++i)
    {
        if( vis[l0[i]]||vis[r0[i]] )
            continue;
        sum=cntji=cntou=cntda=0;
        dfs( (l0[i]?l0[i]:r0[i]) );
        if(cntji==0)
        {
            if(!cntda)
                cntda=1;//鏄竴涓幆
            ans+=cntda;
            ++liansum;
        }
        else
        {
            ans+=cntda;
            liansum+=cntji/2;
        }
    }
    printf("ans=%d liansum=%d\n",ans,liansum);
    return ans+liansum;
}

// 鑷幆涓嶇敤鑰冭檻锛屽洜涓鸿仈閫氬揩閲屽彧鏈変竴涓嚜鐜椂锛屾寜鐓х幆绠?
//  涓嶅彧鏈変竴涓嚜鐜椂锛宒eg[杩欎釜鐐筣>2锛岀啍鏂殑鏃跺€欓『渚跨啍鏂簡
int main(){

    //freopen("frame4.in","r",stdin);

    mem(first,-1);

    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i)
    {
        scanf("%d%d",&l0[i],&r0[i]);
        if(!l0[i])
            l0[i]=++n;
        if(!r0[i])
            r0[i]=++n;// 鍔犱笂鏂扮偣
        ++deg[l0[i]];
        ++deg[r0[i]];
        addbian(l0[i],r0[i]);
        addbian(r0[i],l0[i]);
    }
    cc=0;tot=0;
    for(int i=1;i<=n;++i)
        if(deg[i])
            ++tot;
    for(int i=1;i<=n;++i)
        if(deg[i])
        {
            dfs1(i);
            break;
        }
    if(tot==cc)
        cout<<work1();
    else
        cout<<work2();
}
T2

 

 

T3

我打的不是正解,但是A了,理论复杂度过不了...

f[i][j][k] 第i个平民 j从它到根节点的状态 选了k个平民打仗

转移的时候就求出i和i-1的LCA,然后用一个t[][]数组处理出来i和i-1公共部分 各状态 选择平民打仗数量 的最优解,然后转移即可

正解是 树规 先暴搜出所有状态,再用类似dp的东西统计ans

 

 

技术分享
#pragma GCC optimize("O2")
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
const int N=1106;

ll inf;
int n,m;
int maxp,num,p[14];
ll w[N][N];
int hou[N][14],zhan[N][14];
//int lca[N][N];

ll f[2][N][N];
int now;

void chu()
{
    for(int i=1;i<=num;++i)
        for(int j=0;j<=maxp;++j)
            for(int k=1;k<n;++k)
            {
                if( (j&(1<<k)) && (j&1) )
                    w[i][j]+=zhan[i][k];
                else
                    if( !(j&(1<<k)) && !(j&1) )
                      w[i][j]+=hou[i][k];
            }

    /*int temp,temp1,temp2;
    for(int i=1;i<=num;++i)
        for(int j=i+1;j<=num;++j)
        {
            temp=0;temp1=((1<<(n-1))-1)+i;temp2=((1<<(n-1))-1)+j;
            while(temp1!=temp2)
            {
                ++temp;
                temp1/=2;
                temp2/=2;
            }
            lca[i][j]=temp;
        }*/
}

ll t[N][N];

void out11()
{
    printf("\n");
    for(int i=0;i<=maxp;++i)
    {
        for(int j=1;j<=m;++j)
            printf("%lld ",t[i][j]);
        printf("\n");
    }
    printf("\n");
}

int LCA(int x,int y)
{
    int t1=((1<<(n-1))-1)+x,t2=((1<<(n-1))-1)+y;
    int cc=0;
    while(t1!=t2)
    {
        ++cc;
        t1>>=1;
        t2>>=1;
    }
    return cc;
}

void work()
{
    mem(f,-50);inf=-f[0][0][0];
    for(int i=0;i<=maxp;++i)
        f[0][i][i&1]=w[1][i];
    int temp,temp1,nowp;
    int hhh;
    ll tt=0;
    now=0;
    for(int i=2;i<=num;++i)
    {
        now^=1;

        hhh=(i>m?m:i);

        temp=LCA(i-1,i);temp1=n-temp;

        for(int j=0;j<=p[temp1];++j)
            for(int nu=0;nu<=hhh;++nu)
                f[now][j][nu]=-inf;

        for(int j=0;j<=p[temp1];++j)
        {
            nowp=(j<<temp);
            for(int nu=0;nu<=hhh;++nu)
            {
                t[nowp][nu]=-inf;
                for(int k=0;k<=p[temp];++k)
                    if(t[nowp][nu]<f[now^1][nowp|k][nu])
                        t[nowp][nu]=f[now^1][nowp|k][nu];
                    //t[nowp][nu]=max(t[nowp][nu],f[now^1][nowp|k][nu]);
            }
        }
        //out11();

        for(int j=0;j<=p[temp1];++j)
        {
            nowp=j<<temp;
            for(int nu=0;nu<=hhh;++nu)
            {
                for(int k=0;k<=p[temp];++k)
                {
                    tt=t[nowp][nu]+w[i][nowp|k];
                    if(f[now][nowp|k][nu+(k&1)]<tt)
                        f[now][nowp|k][nu+(k&1)]=tt;
                    //f[now][nowp|k][nu+(k&1)]=max(f[now][nowp|k][nu+(k&1)],t[nowp][nu]+w[i][nowp|k]);
                }
            }
        }
    }

    ll ans=0;
    for(int i=0;i<=maxp;++i)
        for(int j=0;j<=m;++j)
            if(ans<f[now][i][j])
                ans=f[now][i][j];
            //ans=max(ans,f[now][i][j]);
    cout<<ans;
}

//0_houqin 1_zuozhan
int main(){

    //freopen("T3.in","r",stdin);

    for(int i=1;i<=12;++i)
        p[i]=(1<<i)-1;

    scanf("%d%d",&n,&m);
    maxp=(1<<n)-1;num=(1<<(n-1));
    for(int i=1;i<=num;++i)
        for(int j=1;j<n;++j)
            scanf("%d",&zhan[i][j]);
    for(int i=1;i<=num;++i)
        for(int j=1;j<n;++j)
            scanf("%d",&hou[i][j]);
    chu();
    work();
}
T3

 

10.1 考试 ..........

标签:欧拉图   line   namespace   opera   滚动   amp   play   否则   clear   

原文地址:http://www.cnblogs.com/A-LEAF/p/7617313.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!