10.25 考试

T1

太鼓达人...我会说我考试的时候想了半天打表吗?当然不会

开大栈记得要点上执行命令...

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#define ll long long
#define rint register int
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;

int n,len,maxp;
int zhan[(1<<20)+1000],he;
bool flag[(1<<20)+1000];

void dfs(int order,int now)
{
    //printf("order=%d now=%d\n",order,now);
    if(order==len+1)
    {
        if(!now)
        {
            for(int i=1;i<=len;++i)
                printf("%d",zhan[i]);
            printf("\n");
            exit(0);
        }
        return ;
    }
    if(flag[now])
        return ;
    flag[now]=1;
    
    int tt;
    
    tt=(((now<<1)&maxp)|1);
    zhan[++he]=1;
    dfs(order+1,tt);
    --he;
    
    tt=((now<<1)&maxp);
    zhan[++he]=0;
    dfs(order+1,tt);
    --he;
    
    flag[now]=0;
}

int main(){
    
    //freopen("T1biao.out","w",stdout);
    
    scanf("%d",&n);
    len=(1<<n); maxp=(1<<n)-1;
    dfs(1,0);
}
dfs代码

迭代code (你现在应该知道我有多懒了...)

 

T2

树规...

状态数组:

$f_{i,j} 以第i个结点为根的子树走了j个点又回到i的最小花费$

$g_{i,j} 以第i个结点为根的子树走了j个点在任意点停下的最小花费$

然后进行背包就行了,记得枚举已有子树大小和当前加入子树大小,不要在外面枚举总的大小

 

#pragma GCC optimize("O3")
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#define ll long long
#define rint register int
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
inline void read(int &x)
{
    x=0; char q=getchar();
    while(q<'0'||q>'9') q=getchar();
    while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar();
}
const int N=10006;
int first[N*2],nt[N*2],w[N*2],ver[N*2],e;
void addbian(int u,int v,int _w)
{
    w[e]=_w; ver[e]=v;
    nt[e]=first[u];
    first[u]=e++;
}

int n,K,root;
int f[N][N];// 走回来 
int g[N][N];// 不走回来 

int fa[N],size[N];
void dfs(int x)
{
    size[x]=1;
    f[x][0]=f[x][1]=0;
    g[x][0]=g[x][1]=0;
    int i,j,k,t1,t2;
    for(i=first[x];i!=-1;i=nt[i])
    {
        if(ver[i]==fa[x]) continue;
        fa[ver[i]]=x;
        dfs(ver[i]);
        
        for(j=(size[x]<K?size[x]:K);j;--j)
            for(k=0;k<=size[ver[i]];++k)
            {
                if(j+k>K)
                    break;
                t1=f[x][j]+f[ver[i]][k]+w[i]*2;
                if(f[x][j+k]>t1) f[x][j+k]=t1;
                t1=g[x][j]+f[ver[i]][k]+w[i]*2; t2=f[x][j]+g[ver[i]][k]+w[i];
                if(t1>t2) t1=t2;
                if(g[x][j+k]>t1) g[x][j+k]=t1;
            }
        size[x]+=size[ver[i]];
    }
}

int main(){
    
    //freopen("T2.in","r",stdin);
    //freopen("T2.out","w",stdout);
    rint i,j;
    
    mem(first,-1);
    
    read(n); read(K); read(root);
    int tin1,tin2,tin3;
    for(i=1;i<n;++i)
    {
        read(tin1); read(tin2); read(tin3);
        addbian(tin1,tin2,tin3);
        addbian(tin2,tin1,tin3);
    }
    mem(f,60); mem(g,60);
    dfs(root);
    cout<<g[root][K];
}
T2

 

T3

因子个数相同,显然将阶乘分解质因数,然后暴搜

首先你需要一个map记忆化,在搜的时候边乘边除gcd,使它们互质

因为相同的约数是无用的,这样不仅可以减少map的结点,还会变快

然后剪枝

发现2、3、5的数量很多,所以可以预处理出来,每个数对的数量,再开一个map存下来

假设当前dfs的数对是 A,B 它们互质,那么2、3、5贡献的数对必须是 B,A 才会相等

所以正确

还有一个剪枝

大的素数只有一个,所以可以跳过,在最后枚举用组合数计算

但是我没用,因为记忆化搜索够快了

 

/*
我认为把因子个数是1的跳过,在最后处理并不会加快
因为记忆化搜索不会因为这个慢... 
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <map>
#define ll long long
#define rint register int
#define mem(a,b) memset(a,b,sizeof(a))
#define ull unsigned long long
#define dd double
using namespace std;
inline void read(int &x)
{
    x=0; char q=getchar();
    while(q<'0'||q>'9') q=getchar();
    while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar();
}
ll gcd(ll x,ll y){return y==0?x:gcd(y,x%y);}
int intgcd(int x,int y){return y==0?x:gcd(y,x%y);}

struct son
{
    ll s1,s2;
    son(){}
    son(ll _s1,ll _s2)
    {
        s1=_s1; s2=_s2;
    }
    bool friend operator < (son a,son b)
    {
        if(a.s1==b.s1)
            return a.s2<b.s2;
        return a.s1<b.s1;
    }
};

int n;
int num[28];
int prime[106],cnt,top;
bool he[106];
map<son,ll> mp[26];
map<son,int> mm;
void dfs1(int order,int A,int B)
{
    int gg=intgcd(A,B);
    A/=gg; B/=gg;
    if(order==top+1)
    {
        // 这里不能A大B小,不然会重复 
        ++mm[son(A,B)];
        return ;
    }
    for(int i=0;i<=num[order];++i)
        dfs1(order+1,A*(i+1),B*(num[order]-i+1));
}
void chu()
{
    rint i,j;
    
    for(i=2;i<=n;++i)
    {
        if(!he[i])
            prime[++cnt]=i;
        for(j=1;j<=cnt&&i*prime[j]<=n;++j)
        {
            he[i*prime[j]]=1;
            if(i%prime[j]==0)
                break;
        }
    }
    int tt;
    for(i=1;i<=n;++i)
    {
        tt=i;
        for(j=1;j<=cnt;++j)
            while(tt%prime[j]==0)
            {
                ++num[j];
                tt/=prime[j];
            }
    }
    top=min(3,cnt);
    dfs1(1,1,1);
}

ll dfs(int order,ll A,ll B)
{
    ll gg=gcd(A,B);
    A/=gg; B/=gg;
    if(A>B) A^=B,B^=A,A^=B; // A大B小可以优化掉一半 
    son hh=(son){A,B};
    if(order==top)
    {
        if(mm.count(hh))
            return mm[hh];
        return 0;
    }
    if(mp[order].count(hh))
        return mp[order][hh];
    ll as=0;
    for(int i=num[order];i>=0;--i)
        as+=dfs(order-1,A*(i+1),B*(num[order]-i+1));
    mp[order][hh]=as;
    return as;
}

int main(){    
    rint i,j;
    read(n);
    if(n==1)
    {
        printf("1");
        return 0;
    }
    chu();
    printf("%lld",dfs(cnt,1,1)/2);
}
T3

 

posted @ 2017-10-25 19:33  A_LEAF  阅读(174)  评论(0编辑  收藏  举报