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 }
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 }
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 }