2021.10.16

T1:Makik 的能量项链

Problem:

Makik 有一串能量项链,这串项链是从 Mars 母星带来的,作为祖传之宝一直陪伴他。这个项链有 n个能量珠,每个能量珠有一个属性值。于是这 n 个能量珠一共有 k 种属性值(即可能有多个能量珠有同一种属性)。现在 Makik 可以通过特殊的拆解方式,拆解两个位置,使得这一圈能量珠变为两条链状结构。
但是拆解后的能量珠可能会不稳定。Makik 发现当且仅当拆解后的两条链中,没有相同属性的能量珠时,才是稳定结构。
Makik 想知道有多少种拆解方式,以及两条链的长度差的绝对值的最小值。

Solution:

考虑中间的十分,每种颜色值出现了两次

我们可以在一种颜色出现第一次的时候 +1, 出现第二次的时候 -1

那么前缀和相等的一对点一定可以成为一对分割点

如果颜色出现了不止一次的话,+1,-1显然不行

所以我们可以每次加减一个不同的很大整数来避免重复

Code:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=1e6+100;
 4 typedef unsigned long long ull;
 5 typedef long long LL;
 6 const ull base1=19941007;
 7 const ull base2=1321;
 8 int n,k,ans,cnt;
 9 int a[N<<1];
10 int t[N],temp[N];
11 int Abs(int x){
12     return x<0?-x:x;
13 }
14 void force(){
15     ans=n;
16     for(int i=1;i<=n;++i){
17         scanf("%d",&a[i]);
18         a[i+n]=a[i];
19         t[a[i]]++;
20     }
21     int flag=1;
22     for(int i=1;i<=n;++i){
23         for(int j=i;j<=n*2;++j){
24             flag=1;
25             for(int s=i;s<=j;++s) temp[a[s]]++;
26             for(int s=1;s<=k;++s){
27                 if(temp[s]&&temp[s]!=t[s]){
28                     flag=0;
29                     break;
30                 }
31             }
32             if(flag&&!(j-i+1==n)){
33                 ans=min(ans,Abs(n-2*(j-i+1)));
34                 cnt++;
35             }
36             for(int s=i;s<=j;++s) temp[a[s]]--;
37         }
38     }
39     printf("%d %d",cnt/2,ans);
40 }
41 ull Hash1[N],Hash2[N];
42 void Get_hash(int n){
43     Hash1[0]=1;
44     Hash2[0]=1;
45     for(int i=1;i<=n;++i) Hash1[i]=Hash1[i-1]*base1;
46     for(int i=1;i<=n;++i) Hash2[i]=Hash2[i-1]*base2;
47 }
48 int b[N];
49 struct hx{
50     ull t1,t2;
51     int pos;
52     bool operator < (const hx &a) const { 
53         if(t1!=a.t1) return t1<a.t1;
54         else if(t2!=a.t2) return t2<a.t2;
55         else return pos<a.pos;
56     }
57 }T[N];
58 int main(){
59     scanf("%d%d",&n,&k);
60     Get_hash(k);
61     for(int i=1;i<=n;++i) scanf("%d",&a[i]);
62     for(int i=n;i>=1;--i) if(!b[a[i]]) b[a[i]]=i;
63     ull s1=0,s2=0;
64     for(int i=1;i<=n;++i){
65         s1=s1+Hash1[a[i]];
66         s2=s2+Hash2[a[i]];
67         t[a[i]]++;
68         if(b[a[i]]==i){
69             s1=s1-Hash1[a[i]]*t[a[i]];
70             s2=s2-Hash2[a[i]]*t[a[i]];
71         }
72         T[i].t1=s1;
73         T[i].t2=s2;
74         T[i].pos=i;
75     }
76     sort(T+1,T+1+n);
77     LL cnt=0;
78     int ans=n,l=1,r=0,ans1,ans2,i,j;
79     int mid=(n+1)>>1;
80     for(i=1;i<=n;++i){
81         j=i;
82         while(T[j].t1==T[i].t1&&T[j].t2==T[i].t2&&j<=n) j++; 
83         cnt+=1LL*(j-i)*(j-i-1)/2;
84         for(l=i,r=i;r<=j-1;r++){
85             ans1=ans2=n;
86             while(l<r&&T[r].pos-T[l].pos>=mid) l++;
87             ans1=Abs(n-2*(T[r].pos-T[l].pos));
88             if(l>i) ans2=Abs(n-2*(T[r].pos-T[l-1].pos));
89             ans=min(ans,min(ans1,ans2));
90         }
91         i=j-1;
92     }
93     printf("%lld %d\n",cnt,ans);
94     return 0;
95 }

T2:Makik 开飞机

Problem:

Makik 在达到世界首富之后,面对自己开遍全球的随处可见的富丽堂皇的金库巨大的银行感到索然无味,于是他买了一架私人定制飞机开始挑战极限:在地球的赤道进行一圈的飞行环游。当然他考虑过带着马仔驾驶飞机进行空中加油,但低调的他还是选择在赤道上自己开的飞机场加油。
现在给出你 Makik 在赤道开的 n 个飞机场,飞机场可以进行飞机的加油。
Makik 有 s 架飞机型号并且知道每种型号每次加油后最长的飞行距离 d,并向你询问每种型号包括最后一次降落加油的降落加油次数最少是多少

Solution:

思博题

倍长之后 O(n) 看一下每个点往后最大能到哪,向他连条边,这样就形成了一棵树

接下来的问题就变成普及组倍增/二分了

Code:

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 const int maxn=2000005;
 5 int n,m,u,s[maxn],f[maxn],st[maxn];
 6 int main(){
 7     scanf("%d%d",&n,&m);
 8     for(int i=1;i<=n;i++){
 9         int x;
10         scanf("%d",&x);
11         if(u<x) u=x;
12         s[i]=s[i-1]+x;
13     }
14     for(int i=n+1;i<=n+n;i++) s[i]=s[i-1]+s[i-n]-s[i-n-1];
15     for(int i=1;i<=n;i++) st[i]=i,f[i]=0;
16     while(m--){
17         int d;
18         scanf("%d",&d);
19         if(d<u){
20             puts("NIE");
21             continue;
22         }
23         int j=1;
24         for(int i=n+1;;i++){
25             while(s[i]-s[j]>d) j++;
26             f[i]=f[j]+1;
27             st[i]=st[j];
28             if(i-st[i]>=n){
29                 printf("%d\n",f[i]);
30                 break;
31             }
32         }
33     }
34     return 0;
35 }

T3:Makik 剩单

Problem:

Makik 有一棵圣诞树,这棵树非常巨大,上面满满的陈列着各种剩单礼物,一共有 n 个。
但是冬天到了,由于 Makik 本质是鸽子,所以忘记了浇水,于是整棵圣诞树只有树枝。从图论上看,这也是数学中的树形结构,巧的是,这棵树恰有 n 个节点,n-1 条边,且无环,每个礼物都挂在了节点上,节点之间有边相连通(即点和边构成的树形结构)。
现在 Makik 想知道其中优美圣诞结构的个数。
一个优美圣诞结构定义为:三个圣诞礼物两两之间的距离都相同的结构。

Solution:

很强的一个题,先考虑暴力

暴力01:对每个点都大力BFS,我觉得这个我不用讲

暴力02:树形 DP

考虑这样一个问题,要怎么样的点才能满足三个点两两距离相等呢?

1、存在三个点有共同的 lca。

2、存在一个点,使得它到它两颗不同的子树种两点的距离为 d 且它存在 d 级祖先。

大力 DP

f(x,i) 表示以 x 为根的子树中,距离 x 为 i 的点数

g(x,i) 表示以 x 为根的子树中, 形如下图的的 (a,b) 数量

 

其中 d 可以是任意值(说白了就是都考虑进去),或者说只要在上面街上一个长度为 i 的边就可以构成一个合法的三元组。

考虑转移,枚举 x 的下一个儿子 u

g(x,i) += f(x,i)\times f(u,i-1) + g(u,i+1)

f(x,i) += f(u,i-1)

Code:

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 const int maxn=100010;
 5 struct vec{
 6     int to;
 7     int fro;
 8 }mp[maxn*2];
 9 int tai[maxn],cnt;
10 ll memp[maxn*5];
11 ll *f[maxn],*g[maxn];
12 int mx[maxn];
13 int dep[maxn];
14 ll *wzh=memp+5;
15 int n;
16 ll ans;
17 inline void be(int x,int y){
18     mp[++cnt].to=y;
19     mp[cnt].fro=tai[x];
20     tai[x]=cnt;
21 }
22 inline void bde(int x,int y){
23     be(x,y);
24     be(y,x);
25 }
26 void dfs1(int x,int F){
27     int i,y;
28     mx[x]=x;
29     for(i=tai[x];i;i=mp[i].fro){
30         y=mp[i].to;
31         if(y!=F){
32             dep[y]=dep[x]+1;
33             dfs1(y,x);
34             if(dep[mx[y]]>dep[mx[x]]){
35                 mx[x]=mx[y];
36             }
37         }
38     }
39     for(i=tai[x];i;i=mp[i].fro){
40         y=mp[i].to;
41         if(y!=F&&(mx[y]!=mx[x]||x==1)){
42             y=mx[y];
43             wzh+=dep[y]-dep[x]+1;
44             f[y]=wzh;
45             g[y]=(wzh+=1);
46             wzh+=(dep[y]-dep[x])*2+1;
47         }
48     }
49 }
50 void dp(int x,int F){
51     int i,j,y,z;
52     for(i=tai[x];i;i=mp[i].fro){
53         y=mp[i].to;
54         if(y==F) continue ;
55         dp(y,x);
56         if(mx[y]==mx[x]){
57             f[x]=f[y]-1;
58             g[x]=g[y]+1;
59         }
60     }
61     ans+=g[x][0];
62     f[x][0]=1;
63     for(i=tai[x];i;i=mp[i].fro){
64         y=mp[i].to;
65         if(y==F||mx[y]==mx[x]) continue ;
66         for(j=0;j<=dep[mx[y]]-dep[x];j++){
67             ans+=f[x][j-1]*g[y][j]+g[x][j+1]*f[y][j];
68         }
69         for(j=0;j<=dep[mx[y]]-dep[x];j++){
70             g[x][j-1]+=g[y][j];
71             g[x][j+1]+=f[x][j+1]*f[y][j];
72             f[x][j+1]+=f[y][j];
73         }
74     }
75 }
76 int main(){
77     int i,x,y;
78     scanf("%d",&n);
79     for(i=1;i<n;i++){
80         scanf("%d%d",&x,&y);
81         bde(x,y);
82     }
83     while(wzh!=memp){
84         *wzh=0;
85         wzh--;
86     }
87     *wzh=0;
88     wzh+=1;
89     dep[1]=1;
90     dfs1(1,0);
91     dp(1,0);
92     printf("%lld\n",ans);
93     return 0;
94 }
posted @ 2021-10-16 20:30  B_lank  阅读(51)  评论(0)    收藏  举报