SRM 599 DIV1

本文深入探讨了计算机科学领域的优化算法与数据结构的应用,包括但不限于排序算法、动态规划、哈希算法、贪心算法等,以及它们在解决实际问题中的作用与效果。同时,文章也涉及了数据安全、人工智能处理、测试和版本控制等多个关键领域,旨在为开发者提供实用的解决方案和技术洞察。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

 

  

转载于:https://www.cnblogs.com/eggeek/p/3490882.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值