SRM549

250
PointyWizardHats
题意:n个圆锥型小帽子和m个圆锥形大帽子,现在要把一顶小帽子和一顶大帽子组合起来,组合的条件是xxx,问最多能组合多少对

分析:直白的二分图匹配,少见250出这个

600
MagicalHats
题意:一块13*13的板子,一些位置有帽子,某些帽子后面藏有面值不同的硬币,且任意时刻每个帽子后面只有至多一枚硬币,现在要猜K次,魔术师在每次猜之前可以改变硬币所属的帽子(被猜过的地方就不能改了),并且保证任意时刻每行每列帽子数和硬币数的奇偶性相同,你的目标是最大化得到的硬币价值,魔术师的目标,保证最多有13顶帽子

分析:3进制压一下状态,预处理出每个状态是否合法,记忆化搜索一下

950
CosmicBlocks
题意:有6种颜色的砖块,每种有若干个(<=7500),现在要把这些所有砖块搭起来,要求相同颜色的砖块高度相同;定义两种本质不同的方案当且仅当在一种方案中存在一个颜色的砖块在另一个颜色的下面,而在第二种方案中不存在这对颜色,问有多少种方案的拓扑排序种数在[L,R]

分析:因为颜色数只有6,可以爆搜所有方案,判断一下合不合法,判断的时候需要用网络流。不过有一种 2n 枚举行看和是否够的方法可以过,可能是数据问题

class CosmicBlocks {
    public:
    vector<int>V;
    int minWays,maxWays;
    int ans;
    int n;
    int ned[11];
    int cnt[8];
    int bel[11];
    int tot;//maxH+1
    vector<int>G[11];//edge
    vector<int>has[11];//v in hi
    int fa[7];
    int occ[7];
    int dp[(1<<6)+3];
    bool check(){
        for(int i=1;i<tot;i++){
        vector<int>tmpV=V;
        for(int j=0;j<has[i].size();j++){
            int u=has[i][j];
            for(int it=0;it<G[u].size();it++){
                int v=G[u][it];
                tmpV[v]--;
                tmpV[u]--;
            }
        }
        for(int j=0;j<n;j++)if(tmpV[j]<0)return 0;
        for(int mask=0;mask<1<<has[i].size();mask++){
            memset(occ,0,sizeof(occ));
            int nedcost=0,hascost=0;
            for(int j=0;j<has[i].size();j++){
                if(mask>>j&1){
                    int u=has[i][j];
                    nedcost+=tmpV[u];
                    for(int k=0;k<G[u].size();k++){
                        if(!occ[G[u][k]]){
                            occ[G[u][k]]=1;
                            hascost+=tmpV[G[u][k]]; 
                        }
                    }
                }
            }
            if(nedcost>hascost)return 0;
        }
    }
    memset(dp,0,sizeof(dp));
    memset(fa,0,sizeof(fa));
    dp[0]=1;
    for(int i=0;i<n;i++){
        for(int j=0;j<G[i].size();j++){
            fa[G[i][j]]|=(1<<i);
        }
    }
    for(int mask=0;mask<1<<n;mask++){
        for(int i=0;i<n;i++){
            if(mask>>i&1)continue;
            if((mask|fa[i])!=mask)continue;
            dp[mask|(1<<i)]+=dp[mask];
        }
    }
    //printf("dp=%d\n",dp[(1<<n)-1]);
    return dp[(1<<n)-1]>=minWays&&dp[(1<<n)-1]<=maxWays;
    }
    void dfs3(int cur){
        if(cur>=n){
        /*
        puts("haaha");
        for(int i=0;i<n;i++){
            printf("%d: ",i);
            for(int j=0;j<G[i].size();j++){
                printf("%d ",G[i][j]);
            }
            puts("");
        }
        */
        if(check())ans++;
        return;
    }
    int h=bel[cur];
    if(!h){G[cur].clear();dfs3(cur+1);}
    else{
        int bef=(int)has[h-1].size();
        for(int mask=1;mask<1<<bef;mask++){
            G[cur].clear();
            for(int j=0;j<bef;j++){
                if(mask>>j&1){
                    G[cur].push_back(has[h-1][j]);
                }
            }
            dfs3(cur+1);
        }
    }
    }
    void dfs2(int cur){
    if(cur>=n){
        for(int i=0;i<tot;i++)has[i].clear();
        for(int i=0;i<n;i++)has[bel[i]].push_back(i);
        //for(int i=0;i<n;i++)printf("%d ",bel[i]);puts("");
        dfs3(0);
        //printf("tmpans=%d\n",ans);
        //exit(0);
        return;
    }
        for(int i=0;i<tot;i++){
        if(cnt[i]<ned[i]){
            cnt[i]++;
            bel[cur]=i;
            dfs2(cur+1);
            cnt[i]--;
        }
    }
    }
    void dfs1(int cur,int rest){
        if(!rest){
        memset(cnt,0,sizeof(cnt));
        tot=cur;
        //for(int i=0;i<tot;i++){printf("%d ",ned[i]);}puts("");
        dfs2(0);
        //printf("ans=%d\n",ans);
        //exit(0);
        return;
    }
    for(int i=1;i<=rest;i++){
        ned[cur]=i;
        dfs1(cur+1,rest-i);
    }
    }
    int getNumOrders(vector<int> blockTypes, int minWays, int maxWays) {
    V=blockTypes;
    this->minWays=minWays;
    this->maxWays=maxWays;
    n=blockTypes.size();
    ans=0;
    dfs1(0,n);
    return ans;
        return 0;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值