2016_1_17_第二题

这道题调了大概一个多小时终于过了,有许多地方我希望记清楚,我还是记下来。

先给上代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <cmath>
 6 using namespace std;
 7 const int N = 3003;
 8 int n;
 9 int prime[N],pd,t,record[N];
10 bool vis[N];
11 int small[N],ts,tot;
12 int big[N],tb;
13 int biao[603][1003],size[1003];
14 long long dp[(1<<16)+10][603];
15 void dfs(int i,int linshi,int t,long long kk) {
16     if(t > ts) return;
17     if(kk*small[t]<=n) {
18         biao[i][++size[i]] = linshi+(1<<(t-1));
19         dfs(i,linshi+(1<<(t-1)),t+1,kk*small[t]);
20         dfs(i,linshi,t+1,kk);
21     }
22 }
23 inline void solve(int n) {
24     int k;
25     for(int s = 2 ; s <= n ; ++s) {
26         if(!vis[s]) prime[++t] = s;
27         for(int j = 1 ; j <= t && (k=prime[j]*s)<=n ; ++j) {
28             vis[k] = true;
29             if(s%prime[j]==0) break;
30         }
31     }
32     for(int i = 1 ; i <= n ; ++i) {
33         int linshi = i;
34         for(int j = 1 ; j <= t && linshi!=1 ; ++j) {
35             while(linshi%prime[j]==0 && linshi!=1) {
36                 linshi/=prime[j];
37                 record[prime[j]]++;
38             }
39         }
40     }
41     pd = sqrt(n);
42     for(int i = 1 ; i <= n ; ++i) {
43         if(record[i]%2==1) {
44             if(i<pd) small[++ts] = i;
45             else big[++tb] = i;
46         }
47     }
48     tot = ts+tb;
49     for(int i = 1 ; i <= ts ; ++i) dfs(i,(1<<(i-1)),i+1,small[i]),biao[i][++size[i]] = (1<<(i-1));
50     for(int i = 1 ; i <= tb ; ++i) dfs(i+ts,0,1,big[i]);
51     int end = (1<<ts)-1;
52     dp[end][1] = 1;
53     for(int i = 1 ; i <= tot ; ++i) {
54         for(int j = 0 ; j <= end ; ++j) {
55             if(dp[j][i]==0) continue;
56             dp[j][i+1] = dp[j][i];
57             for(int k = 1 ; k <= size[i] ; ++k)
58                 if((biao[i][k]&j)==biao[i][k]) dp[j-biao[i][k]][i+1] += dp[j][i];
59         }
60     }
61     printf("%lld",dp[0][tot]*2);
62 }
63 int main() {
64     freopen("test.in","r",stdin);
65     freopen("test.out","w",stdout);
66     scanf("%d",&n);
67     solve(n);
68 }
View Code

首先感觉那个DFS是可以直接做的,就是可以直接转移的,当时受了同学的蛊惑我于是打了个转移表。反正还是蛮优的,然后这道题重点就是DP了,最开始我只想考虑大质数的时候是可能有问题的。所以我把小质数加上来一起搞,可以处理出只选大质数的时候的方案。代码还是可以好好感受感受在最后一步J到大质数J+1的时候,我就可以知道集合s为各个状态时I的方案,然后就可以累加起来咯。

隔两天再看看,别忘了蛤蛤!

原文地址:https://www.cnblogs.com/registerzxr/p/5149017.html