• NOI2015 寿司晚宴


    题意:

    给定$n$,对于$[2,n]$中的每个正整数,从中选出两个集合,使得两个集合各自的LCM互质,答案对$p$取模.

    $n<=500,p<=1^{9}$

    题解:

    暴力做法,预处理出$<=n$的所有素因子.

    进行状压DP,$dp[i][a][b]$表示前$i$个点,所选集合中的素因子集合分别为$a$,$b$的方案数.

    可以通过$30%$的数据.

    我们需要优化该算法.

    原算法中考虑了每一个素因子,考虑能否减少素因子的个数来优化算法呢?

    首先,大于$n/2$的素因子是不用考虑的,因为最多只存在一个数字含有该素因子.

    但是$<=n/2$的素因子还是很多,这样起不到实质性的优化,如果考虑$sqrt{n}$内的素因子的呢?

    这样每个数字最多只会含有一个>$sqrt{n}$的因子,假设为$k$.

    按照原来的思路DP,$dp[i][a][b]$表示前$i$个点,所选集合中的素因子集合分别为$a$,$b$的方案数.

    但是我们还要考虑$k$对答案的影响.

    只要我们把$k$相同的元素放在一起考虑.

    那么就有三种选择,选出一个集合全部在$a$,全部在$b$,都不选.

    那么只要分别对放在$a$,放在$b$进行DP即可.

    这样就可以把素因子的个数减少到8个,而DP的复杂度却没有升高.

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int M=505,S=8;
    int n,P,mark[M],pri[M],m=0;
    int f[M][1<<S][1<<S],t[1<<S][1<<S];//3qw
    struct node{
        int v,p;
        bool operator<(const node &tmp)const{
            return p<tmp.p;
        }
        bool operator==(const node &tmp)const{
            return p==tmp.p&&(p!=1||v==tmp.v);
        }
    }w[M];
    void init(){
        int mx=sqrt(n),i,j,k;
        for(i=2;i<=n;i++)w[i].p=i;
        for(i=2;i<=mx;i++){
            if(mark[i])continue;
            pri[m]=i;
            for(j=i;j<=n;j+=i){
                w[j].v|=(1<<m);
                while(w[j].p%i==0)w[j].p/=i;
                mark[j]=1;
            }
            m++;
        }
        sort(w+2,w+1+n);//从第二个数字开始 
    }
    void Add(int &x,int y){x+=y;if(x>=P)x-=P;if(x<0)x+=P;}
    int main(){
        scanf("%d %d",&n,&P);
        init();
        int i,j,k,en,ful=(1<<m)-1,a,b,v;
        f[1][0][0]=t[0][0]=1;
        for(i=2;i<=n;i=en){ 
            for(j=0;j<=ful;j++){
                for(k=0;k<=ful;k++){
                    t[j][k]=f[i-1][j][k];
                }
            }
            for(j=i;j<=n&&w[j]==w[i];j++);
            en=j;
            for(j=i;j<en;j++){
                v=w[j].v;
                for(a=ful;a>=0;a--){
                    for(b=ful;b>=0;b--){
                        if(a&b)continue;
                        if(b&v)continue;
                        Add(t[a|v][b],t[a][b]);
                    }
                }
            }
            for(a=0;a<=ful;a++){
                for(b=0;b<=ful;b++){
                    Add(f[en-1][a][b],t[a][b]);
                    Add(f[en-1][a][b],-f[i-1][a][b]);
                    t[a][b]=f[i-1][a][b];
                }
            }
            for(j=i;j<en;j++){
                v=w[j].v;
                for(a=ful;a>=0;a--){
                    for(b=ful;b>=0;b--){
                        if(a&b)continue;
                        if(a&v)continue;
                        Add(t[a][b|v],t[a][b]);
                    }
                }
            }
            for(a=0;a<=ful;a++){
                for(b=0;b<=ful;b++){
                    Add(f[en-1][a][b],t[a][b]);
                }
            }
        }
        int ans=0;
        for(i=0;i<=ful;i++){
            for(j=0;j<=ful;j++){
                if(!(i&j))Add(ans,f[n][i][j]);
            }
        }
        printf("%d
    ",ans);
        return 0;
    }
    View Code

    $By LIN452$

    $2017.06.08$

  • 相关阅读:
    【WPF】 Prism 框架中,TabControl 作为Region时如何设置Header
    【WPF】将控件事件中的参数,传递到ViewModel中
    WPF 一种带有多个子集的类ComBox 解决方法
    WPF TabControl美化
    【WPF】 问题总结-RaidButton修改样式模板后作用区域的变化
    C# 打开Excel文件
    获取文件夹下所有的文件名
    访问需要HTTP Basic Authentication认证的资源的c#的实现 将账号密码放入url
    第十三章 建造者模式(Builder)
    第十二章 外观模式 (Facade)
  • 原文地址:https://www.cnblogs.com/Lay-with-me/p/6956638.html
Copyright © 2020-2023  润新知