zoukankan      html  css  js  c++  java
  • 【LOJ】#2131. 「NOI2015」寿司晚宴

    题解

    怎么NOI2015D1……全是一眼秒的sb题……然后我代码全都写跪一遍= = 要是NOI2015是IOI赛制我就可以AK啦(大雾)
    代码能力直线下降,NOI2018滚粗预定了啊TAT
    我是不是要去开码农题啊QAQ

    我们发现大于(sqrt{N})的素数只会在每个数里出现至多1个,而小于(sqrt{N})的素数只有8个
    分别是
    2 3 5 7 11 13 17 19

    我们对于素因子只有这8个的数先做一遍dp,状态压缩是(3^8)每一位分别是0 1 2,表示这个素因子不在任何集合,这个素因子在1集合和这个素因子在2集合
    每次判断这个数的素因子如果跨了两个集合就不合法,如果和1集合有交不可以放到2集合,和2集合有交不可以放到1集合

    对于包含剩下素数的数,设这个大于(sqrt{N})的素数为p,按照上述过程做dp,设f[S]为1集合里包含有p作为素因子的数,g[S]为2集合里包含有p作为素因子的数
    最后ans[S] = f[S] + g[S] - dp[S](dp[S]是只包含8个素因子的数的方案数)

    复杂度(O(3^8 N))

    代码

    #include <bits/stdc++.h>
    //#define ivorysi
    #define enter putchar('
    ')
    #define space putchar(' ')
    #define fi first
    #define se second
    #define pb push_back
    #define mp make_pair
    #define eps 1e-8
    #define mo 974711
    #define MAXN 100005
    #define pii pair<int,int>
    using namespace std;
    typedef long long int64;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;char c = getchar();T f = 1;
        while(c < '0' || c > '9') {
    	if(c == '-') f = -1;
    	c = getchar();
        }
        while(c >= '0' && c <= '9') {
    	res = res * 10 + c - '0';
    	c = getchar();
        }
        res *= f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {putchar('-');x = -x;}
        if(x >= 10) {
    	out(x / 10);
        }
        putchar('0' + x % 10);
    }
    bool nonprime[505];
    int prime[505],tot;
    int dp[2][7006],N,MOD,S[505],rem[505],a[10],b[10],f[2][7006],g[2][7006],s[7006];
    int encode(int *a) {
        int res = 0;
        for(int i = 1 ; i <= 8 ; ++i) {
    	res = res * 3 + a[i];
        }
        return res;
    }
    void decode(int Sta,int *a) {
        for(int i = 8 ; i >= 1 ; --i) {
    	a[i] = Sta % 3;
    	Sta /= 3;
        }
    }
    int mul(int a,int b) {
        return 1LL * a * b % MOD;
    }
    int inc(int a,int b) {
        a = a + b;
        if(a >= MOD) a -= MOD;
        return a;
    }
    void update(int &x,int y) {
        x = x + y;
        if(x >= MOD) x -= MOD;
    }
    void Init() {
        read(N);read(MOD);
        for(int i = 2 ; i <= 500 ; ++i) {
    	if(!nonprime[i]) {
    	    prime[++tot] = i;
    	    for(int j = 2 ; j <= 500 / i ; ++j) nonprime[i * j] = 1;
    	}
        }
    }
    void Solve() {
        for(int i = 2 ; i <= N ; ++i) {
    	int x = i;
    	for(int j = 1 ; j <= 8 ; ++j) {
    	    if(x % prime[j] == 0) {
    		S[i] |= (1 << j - 1);
    		while(x % prime[j] == 0) x /= prime[j];
    	    }
    	}
    	if(x > 1) rem[i] = x;
        }
        int t = 1;
        for(int j = 1 ; j <= 8 ; ++j) t = t * 3;
        int cur = 0;
        dp[0][0] = 1;
        for(int i = 2 ; i <= N ; ++i) {
    	if(rem[i]) continue;
    	memset(dp[cur ^ 1],0,sizeof(dp[cur ^ 1]));
    	for(int j = 0 ; j < t ; ++j) {
    	    if(!dp[cur][j]) continue;
    	    decode(j,a);
    	    int s1 = 0,s2 = 0;
    	    for(int k = 1 ; k <= 8 ; ++k) {
    		if(a[k] == 1) s1 |= (1 << k - 1);
    		else if(a[k] == 2) s2 |= (1 << k - 1);
    	    }
    	    update(dp[cur ^ 1][j],dp[cur][j]);
    	    if((s1 & S[i]) && (s2 & S[i])) continue;
    	    if(!(s2 & S[i])) {
    		memcpy(b,a,sizeof(a));
    		for(int k = 1 ; k <= 8 ; ++k) {
    		    if(b[k]) continue;
    		    if(S[i] >> (k - 1) & 1) b[k] = 1;
    		}
    		update(dp[cur ^ 1][encode(b)],dp[cur][j]);
    	    }
    	    if(!(s1 & S[i])) {
    		memcpy(b,a,sizeof(a));
    		for(int k = 1 ; k <= 8 ; ++k) {
    		    if(b[k]) continue;
    		    if(S[i] >> (k - 1) & 1) b[k] = 2;
    		}
    		update(dp[cur ^ 1][encode(b)],dp[cur][j]);
    	    }
    	}
    	cur ^= 1;
        }
        int ans = 0;
        for(int i = 9 ; i <= tot ; ++i) {
    	if(N < prime[i]) break;
    	int c = 0;
    	memcpy(f[c],dp[cur],sizeof(dp[cur]));
    	memcpy(g[c],dp[cur],sizeof(dp[cur]));
    	for(int j = 1 ; j <= N / prime[i] ; ++j) {
    	    memset(f[c ^ 1],0,sizeof(f[c ^ 1]));
    	    memset(g[c ^ 1],0,sizeof(g[c ^ 1]));
    	    for(int k = 0 ; k < t ; ++k) {
    		decode(k,a);
    		update(f[c ^ 1][k],f[c][k]);
    		update(g[c ^ 1][k],g[c][k]);
    		int s1 = 0,s2 = 0;
    		for(int h = 1 ; h <= 8 ; ++h) {
    		    if(a[h] == 1) s1 |= (1 << h - 1);
    		    else if(a[h] == 2) s2 |= (1 << h - 1);
    		}
    		if((S[j] & s1) && (S[j] & s2)) continue;
    		if(!(S[j] & s2)) {
    		    memcpy(b,a,sizeof(b));
    		    for(int h = 1 ; h <= 8 ; ++h) {
    			if(b[h]) continue;
    			if(S[j] >> (h - 1) & 1) b[h] = 1;
    		    }
    		    update(f[c ^ 1][encode(b)],f[c][k]);
    		}
    		if(!(S[j] & s1)) {
    		    memcpy(b,a,sizeof(b));
    		    for(int h = 1 ; h <= 8 ; ++h) {
    			if(b[h]) continue;
    			if(S[j] >> (h - 1) & 1) b[h] = 2;
    		    }
    		    update(g[c ^ 1][encode(b)],g[c][k]);
    		}
    	    }
    	    c ^= 1;
    	}
    	for(int k = 0 ; k < t ; ++k) dp[cur][k] = inc(inc(f[c][k],g[c][k]),MOD - dp[cur][k]);
        }
        for(int k = 0 ; k < t ; ++k) update(ans,dp[cur][k]);
        out(ans);enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Init();
        Solve();
        return 0;
    }
    
  • 相关阅读:
    [中文翻译] ASP.NET 5 简介(Introducing ASP.NET 5,原作ScottGu 2015/2/23)
    会写网页 就会写手机APP #2-- 范例修正 , Hybrid Mobile Apps for ASP.NET Developers (Apache Cordova)
    vue事件处理
    vue渲染
    vue数组和对象方法
    vue样式绑定
    vue模板语法与绑定指令
    墨刀的使用
    ajax基础一
    解构赋值中圆括号问题及解构赋值的用途
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9166340.html
Copyright © 2011-2022 走看看