SRM 599 DIV1

A

  首先发现对于2操作,每种素因子可以单独考虑,然后取出步数最多的计入答案,然后分别加上对每种素因子的1操作;

  第二步我犯了个错误,以为最优方案是把素因子指数按二进制操作,在1的位置执行1操作,0的位置执行2操作倍增;

  然后发现是错的,执行一次1操作后,之后的2操作可以完全代替1操作,这样可以节省对其他素因子的1操作...

  

 1 int getbit(int x)

 2 {

 3     int cur=1,res=0;

 4     while (cur<x) cur+=cur,res++;

 5     return res;

 6 }

 7 int BigFatInteger::minOperations(int A, int B) 

 8 {

 9     initprm();

10     int ans=0,p=0;

11     for (int i=0 ; i<cnt ; i++) if (A%prm[i]==0)

12     {

13         int t=0;

14         while (A%prm[i]==0) A/=prm[i],t+=B;

15         ans ++;

16         p = max(p,getbit(t));

17     }

18     return ans+p;

19 }
View Code

 

B

  题解的思路真的很棒...

  首先为了简化问题,需要猜想+证明一些性质:

  1) 每条边必须是整数; (无理数+无理数=无理数...)

  2) L不能是奇数; (基于性质1,因为多边形形成闭合回路,坐标的奇偶变化是偶数,x0->x0,y0->y0)

  接下来发现L为偶数的时候可以构造出rectangle,于是问题化简为找到一个满足要求的triangle.

  然后根据格点的离散性,对称性,可以把可能的点集缩小,最后o(n2)的暴力枚举/打表.

 1 struct node{int x,y;};

 2 vector<node>p;

 3 vector<int>d;

 4 int sqt[INF+1];

 5 bool check(int x,int y)

 6 {

 7     int dist = x*x+y*y;

 8     if (dist>=INF || !sqt[dist]) return false;

 9     d.push_back(sqt[dist]);

10     return true;

11 }

12 int getdist(node a,node b)

13 {

14     int tmp = (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);

15     if (tmp>=INF || !sqt[tmp]) return INF;

16     return sqt[tmp];

17 }

18 double find(int l)

19 {

20     double res = -1e20;

21     for (int x=0 ; x<=l/2 ; x++ )

22     for (int y=1 ; y<=l/2 ; y++ )

23     if (check(x,y)) p.push_back((node){x,y});

24     int n = p.size();

25     for (int i=0 ; i<n ; i++ )

26     for (int j=i+1 ; j<n ; j++ ) if(d[i]+d[j]<l)

27     {

28         int t = getdist(p[i],p[j]);

29         if (d[i]+d[j]+t!=l) continue;

30         if (p[i].y*p[j].x==p[i].x*p[j].y) continue;

31         int tmp = max(d[i],max(d[j],t)) - min(d[i],min(d[j],t));

32         if (res<0 || res>tmp) res=tmp;

33     }

34     return res;

35 }

36 double FindPolygons::minimumPolygon(int L) 

37 {

38     if (L%2 || L<4) return -1.0;

39     else

40     {

41         for (int i=1 ; i<=2500 ; i++ ) sqt[i*i]=i;

42         double ans = find(L);

43         if (ans>=0.0) return ans;

44         else return (L%4==0)?0:1;

45     }

46 }
View Code

 

C

  不在info中的点可以乘一个排列数,问题化简为求满足info的方案数.

  如果确定了info1[i]为a,那么info2[i]只能选取以a为前缀的集合...

  如果info2[i]在info1中还出现过,可以递推下去考虑...

  然后就会发现这个问题涉及到一个树形结构.

  把所有string造成一棵前缀树,重述问题就是:假设info1[i]位置放a,info2[i]位置只能在a的子树中.

  f(x,mask) 表示当前在第i个节点,分配mask集合的方案数.

  答案就是f(root,11..1).

  对于每个f(x,mask)有两种决策,分配给x,不分配.

  然后解决子问题g(x,son,mask2) 表示给x的son分配剩下mask的方案数.

  优化:预处理所有合法状态的转移.

  

 1 const int mod = (int)1e9 + 7;

 2 class SimilarNames {

 3 public:

 4     int count(vector <string>, vector <int>, vector <int>);

 5 };

 6 vector<int>valid,nxt[MASK],sub[MASK],e[maxn];

 7 map<int,int>ha;

 8 const int root = 51;

 9 int n,m,k,id[MASK];

10 int getk(vector<int>u,vector<int>v){

11     for (int i=0 ; i<m ; i++ ){

12         if (!ha.count(u[i])) u[i]=ha[u[i]]=ha.size()-1;

13         if (!ha.count(v[i])) v[i]=ha[v[i]]=ha.size()-1;

14     }

15     return ha.size();

16 }

17 void buildtree(vector<string>names){

18     sort(names.begin(),names.end());

19     for (int i=0 ; i<n ; i++ ){

20         int fa = root;

21         for (int j=i-1 ; j>=0 ; j-- )

22         if (names[i].substr(0,names[j].size())==names[j]){

23             fa = j;break;

24         }

25         e[fa].push_back(i);

26     }

27 }

28 void pretreat(vector<int>u,vector<int>v){

29     memset(id,-1,sizeof(id));

30     for (int i=0,j ; i<(1<<k) ; i++ ){

31         for ( j=0 ; j<m ; j++ ){

32             int p = 1<<ha[u[j]];

33             int q = 1<<ha[v[j]];

34             if ((i&p) && ((i&q)==0)) break;

35         }

36         if (j==m) {

37             valid.push_back(i);

38             id[i] = valid.size()-1;

39         }

40     }

41     for (int i=0 ; i<(int)valid.size() ; i++ )

42     for (int j=0 ; j<k ; j++ ) if(valid[i]&(1<<j)){

43         if (id[valid[i]^(1<<j)]!=-1)

44             nxt[i].push_back(id[valid[i]^(1<<j)]);

45     }

46     for (int i=0 ; i<(int)valid.size() ; i++ )

47     for (int j=valid[i] ; ; j=(j-1)&valid[i]){

48         if (id[j]!=-1 && id[valid[i]-j]!=-1)

49             sub[i].push_back(id[j]);

50         if (!j) break;

51     }

52 }

53 int f[maxn][MASK],g[maxn][MASK];

54 int add(int &x,int y){

55     x += y;

56     while (x>=mod) x-=mod;

57     return x;

58 }

59 int getg(int cur,int s,int mask){

60     if (s>=0) return g[e[cur][s]][mask];

61     else return !valid[mask];

62 }

63 void dfs(int cur){

64     int s = e[cur].size();

65     for (int i=0 ; i<s ; i++ )

66         dfs(e[cur][i]);

67 

68     for (int i=0 ; i<s ; i++ ){

69         for (int j=0 ; j<(int)valid.size() ; j++ ){

70             for (int x=0 ; x<(int)sub[j].size() ; x++ ){

71                 int A = valid[j];

72                 int B = valid[sub[j][x]];

73                 int p = getg(cur,i-1,id[B]);

74                 int q = f[e[cur][i]][id[A-B]];

75                 g[e[cur][i]][j] = add(g[e[cur][i]][j],((llong)p*q)%mod);

76             }

77         }

78     }

79 

80     for (int i=0 ; i<(int)valid.size() ; i++ ){

81         f[cur][i] = add(f[cur][i],getg(cur,s-1,i));

82         if (cur!=root){

83             for (int j=0 ; j<(int)nxt[i].size() ; j++ )

84                 f[cur][i] = add(f[cur][i],getg(cur,s-1,nxt[i][j]));

85         }

86     }

87 }

88 int SimilarNames::count(vector <string> names, vector <int> u, vector <int> v){

89     n = names.size();

90     m = u.size();

91     k = getk(u,v);

92     buildtree(names);

93     pretreat(u,v);

94     dfs(root);

95     llong ans = f[root][id[(1<<k)-1]];

96     for (int i=n-k ; i>1 ; i-- ) ans = (llong)(ans*i)%mod;

97     return (int)ans;

98 }
View Code

 

  

你可能感兴趣的:(div)