• 【51Nod1386】双马尾机器人(分块+dp)


    对于这种找互质的数的集合的题,一般是讨论每个数的质因子会不会有重复。

    听说这种互质的题把质因子分为小于 n sqrt{n} n 和大于 n sqrt{n} n 是经典套路?

    因为当 n n n 很小的时候,小于 n sqrt{n} n 的质数并不多。比如对于这一题,小于 N = 1000 sqrt{N=1000} N=1000 的数只有 11 11 11 个。

    那么对于那些只有小于 N sqrt{N} N 的质因子的数进行状压 dp,设 d p ( i , j ) dp(i,j) dp(i,j) 为前 i i i 个数中,所有选出的数的所有质因子的状态为 j j j(只考虑小于 N sqrt N N 的质因子)。

    j j j 的定义:如果选出的数的所有质因子中出现了第 k k k 个质数,那么把 j j j 在二进制下的第 k k k 位设为 1 1 1,否则为 0 0 0

    例如,如果出现了 2 2 2(第 1 1 1 个质数)、 5 5 5(第 3 3 3 个质数)和 7 7 7(第 4 4 4 个质数的话), j j j 就应该是 ( 1101 ) 2 (1101)_2 (1101)2

    那么假设 d p ( i − 1 ) dp(i-1) dp(i1) 都已经计算完毕,现在要计算 d p ( i , j ∣ s t a [ i ] ) dp(i,j|sta[i]) dp(i,jsta[i]),其中 j j j 是某个状态, s t a [ i ] sta[i] sta[i] i i i 的质因子状态。那么现在考虑的是状态 j ∣ s t a [ i ] j|sta[i] jsta[i]

    1. d p ( i , j ∣ s t a [ i ] ) = d p ( i − 1 , j ∣ s t a [ i ] ) dp(i,j|sta[i])=dp(i-1,j|sta[i]) dp(i,jsta[i])=dp(i1,jsta[i])。意思就是前 i − 1 i-1 i1 个数中已经选出了状态 j ∣ s t a [ i ] j|sta[i] jsta[i],那么数 i i i 肯定不能在加入这个方案内(不然不互质),所以选的数不增不减。

    2. d p ( i , j ∣ s t a [ i ] ) = d p ( i − 1 , j + 1 − ( m a x p i > 11 ) ) dp(i,j|sta[i])=dp(i-1,j+1-(maxp_i>11)) dp(i,jsta[i])=dp(i1,j+1(maxpi>11))。意思就是前 i − 1 i-1 i1 个数中已经选出了状态 j j j,那么现在肯定可以加入数 i i i。但是由于我们这里只考虑加入质因子都小于 N sqrt{N} N 的情况,所以要减去一个 m a x p i > 11 maxp_i>11 maxpi>11

    现在对只有小于 N sqrt{N} N 的质因子的数都处理完了,那么对于含有大于 N sqrt{N} N 的质因子的数怎么处理呢?(不妨设所有大于 N sqrt{N} N 小于 N N N 的质数有 m m m 个)

    不难发现,这些数恰好仅含有一个大于 N sqrt{N} N 的质因子。所以我们至少要选 m m m 个数才能保证是“极大方案”。又因为要保证选的数最少,所以要恰好选 m m m 个就行了。

    最后可以把 1 1 1 也取上。

    代码:

    #include<bits/stdc++.h>
    
    #define N 1010
    #define INF 0x7fffffff
    
    using namespace std;
    
    int t,n,k;
    int cnt,prime[N],maxp[N],sta[N];
    int dp[2][1<<12];
    bool notprime[N];
    
    void init()
    {
    	for(int i=2;i<=1000;i++)
    	{
    		if(!notprime[i])
    		{
    			prime[++cnt]=i;
    			maxp[i]=cnt;
    			sta[i]=(cnt<=11?(1<<(cnt-1)):0);
    		}
    		for(int j=1;j<=cnt&&i*prime[j]<=1000;j++)
    		{
    			int v=i*prime[j];
    			notprime[v]=true;
    			maxp[v]=max(maxp[i],j);
    			sta[v]=sta[i]|(j<=11?(1<<(j-1)):0);
    		}
    	}
    }
    
    int main()
    {
    	init();
    	scanf("%d",&t);
    	for(int T=1;T<=t;T++)
    	{
    		scanf("%d%d",&n,&k);
    		int m=1;
    		while(prime[m]<=n) m++;
    		m--;
    		int tmp=max(0,m-11);
    		m=min(m,11);
    		int mpow=(1<<m);
    		for(int i=0;i<mpow;i++) dp[0][i]=INF;
    		dp[0][0]=0;
    		int now=1;
    		for(int i=1;i<=n;i++,now^=1)
    		{
    			for(int j=0;j<mpow;j++) dp[now][j]=dp[now^1][j];
    			if(i==k) continue;
    			for(int j=0;j<mpow;j++)
    				if(!(j&sta[i])&&dp[now^1][j]!=INF)
    					dp[now][j|sta[i]]=min(dp[now^1][j|sta[i]],dp[now^1][j]+1-(maxp[i]>11));
    		}
    		printf("Case #%d: %d
    ",T,dp[now^1][mpow-1]+tmp+(k!=1));
    	}
    	return 0;
    }
    
  • 相关阅读:
    实习第一天
    附加、分离数据库和备份、还原数据库的区别(转载于中雪的BLOG)
    2014-08-29 Last Day
    2014-08-26 解决HttpContext.Current.Session在ashx文件中出现“未将对象引用设置到对象的实例”的问题
    什么是Ajax? (转载于疯狂客的BLOG)
    Response.Expires 属性 (转载于疯狂客的BLOG)
    2014-08-22 关于Response、Request等对象在cs文件中的使用
    ASP.NET获取IP的6种方法(转载于LanceZhang's Tech Blog)
    2014-08-13 SQL语句之Left Join
    2014-08-07 优秀程序员所应具备的思想
  • 原文地址:https://www.cnblogs.com/ez-lcw/p/14448676.html
Copyright © 2020-2023  润新知