辣些数据结构的思维题(思维题好难一个都不会TAT)
洛谷P1268 树的重量
- 我觉得难点在于把每个叶子节点想象成分出来的叉
- 然后如果c是a--b这条边上分出来的,可以通过Dab,Dca,Dcb算出分叉边的长度,
- 长度=(Dac+Dbc-Dab)/2
- 怎么看c到底是哪两条边分叉出来的呢?
- 取最小的(洛谷后面的题解可以看懂)
- 代码:(只有一个测试数据感觉都不知道自己写的到底对不对
1 #include <bits/stdc++.h> 2 #define inf 1e9 3 4 using namespace std; 5 int n; //n<=30 6 int d[50][50]; 7 8 inline int f(int a,int b,int c){ //c是ab分叉,算叉出去那一段长度 9 return (d[a][c]+d[b][c]-d[a][b])/2; 10 } 11 12 int main(){ 13 //freopen("owo.in","r",stdin); 14 while(scanf("%d",&n)==1&&n){ 15 memset(d,0,sizeof(d)); 16 for (int i=1; i<n; i++) for (int j=i+1; j<=n; j++) { scanf("%d",&d[i][j]); d[j][i]=d[i][j]; } 17 int ans=d[1][2]; 18 for (int i=3; i<=n; i++) { //把每个点作为分叉加进来 19 int ta=inf; 20 for (int j=1; j<=i; j++) for (int k=1; k<=i; k++) if(k!=i&&j!=i&&j!=k) ta=min(ta, f(j,k,i) ); 21 ans+=ta; 22 } 23 printf("%d\n",ans); 24 } 25 return 0; 26 }
洛谷P2375 [NOI2014]动物园
- 题意:构造一个
num
数组一一对于字符串SSS的前iii个字符构成的子串,既是它的后缀同时又是它的前缀,并且该后缀与该前缀不重叠,
将这种字符串的数量记作num[i]
- 算两个数组:
- 第一个:jump[i]它第一个不重叠的公共前后缀的位置(类似于next[i],但是不允许前后缀有重叠)
- 第二个:ta[i]对于下标i,它全部的公共前后缀的个数
- 这两个数组都可以通过next[i]求得,然后num[i]就等于 ta[ jump[i] ] 辣。
- 代码:
1 #include <bits/stdc++.h> 2 #define nmax 1000010 3 #define mod 1000000007 4 5 using namespace std; 6 typedef long long ll; 7 char b[nmax]; 8 int num[nmax],ne[nmax],ta[nmax],jump[nmax]; 9 int l; 10 ll ans; 11 12 void init(){ 13 ans=1; 14 memset(num,0,sizeof(num)); 15 memset(ne,0,sizeof(ne)); 16 memset(ta,0,sizeof(ta)); 17 memset(jump,0,sizeof(jump)); 18 } 19 20 void build(){ 21 for (int i=2; i<=l; i++) { 22 int j=ne[i-1]; 23 while( b[j+1]!=b[i] && j ) j=ne[j]; 24 if(b[j+1]==b[i]) ne[i]=j+1; 25 } 26 } 27 28 void b2(){ //它第一个不重叠的公共前后缀的位置 29 for (int i=2; i<=l; i++) { 30 int p=jump[i-1]; 31 if( b[p+1] == b[i] && (p+1)<=(i/2) ) jump[i]=p+1; 32 else { 33 while ( p && ( (p+1)>(i/2) || b[p+1]!=b[i] ) ) p=ne[p]; 34 if(b[p+1]==b[i]) jump[i]=p+1; 35 } 36 } 37 } 38 39 void solve(){ 40 int tmp; 41 for (int i=2; i<=l; i++) { 42 int j=ne[i],pd=i/2; 43 if(j) ta[i]=ta[j]+1; 44 if( jump[i] ) tmp=ta[jump[i]]+1; else tmp=0; 45 ans*=(tmp+1); 46 ans%=mod; 47 } 48 } 49 50 int main(){ 51 int t; 52 cin>>t; 53 while(t--){ 54 init(); 55 scanf("%s",b+1); 56 l=strlen(b+1); 57 build(); 58 b2(); 59 solve(); 60 printf("%lld\n",ans); 61 } 62 return 0; 63 }
CF Round #581 (Div. 2)
- 这道题。。。它给的p1,....,pn里面假设连续三个点 pk,p(k+1),p(k+2) 容易知道如果pk到p(k+2)的最短路是2的话p(k+1)是可以删去的
- 于是愉快的扫一遍每次这样看三个。
- 然后就wa6了
- wa的原因:这里如果pk已经被删去了,是要影响到p(k+1)的。
- 比如p1,p2,p3,p4,如果p2被删,p4,p2的最短路是2,会删3,但是如果p1p4的最短路是2.。。就删错了
- 正确姿势:假设前面已经得到一连串p1~pk,现在最后得到的pk,然后往后面走,走到pj,如果p(j+1)和pk的距离和j+1-k相等的话,就可以把pj删了
- 代码:
1 #include <bits/stdc++.h> 2 #define inf 1e6 3 #define mmax 5000010 4 5 using namespace std; 6 int n,m,ans=0,idx=0; 7 int e[200][200]; 8 int p[mmax],del[mmax]={0}; 9 char in[200]; 10 11 void floyd(){ 12 for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) 13 if(e[i][j]>e[i][k]+e[k][j] ) e[i][j]=e[i][k]+e[k][j]; 14 } 15 16 int main(){ 17 cin>>n; 18 for (int i=1; i<=n; i++) { 19 scanf("%s",in+1); 20 for (int j=1; j<=n; j++) if(in[j]=='1') e[i][j]=1; else e[i][j]=inf; 21 } 22 floyd(); 23 for (int i=1; i<=n; i++) e[i][i]=0; 24 cin>>m; 25 scanf("%d%d",&p[0],&p[1]); 26 if(m==2){ 27 printf("2\n"); 28 printf("%d %d\n",p[0],p[1]); 29 }else{ 30 for (int i=2; i<m; i++) { 31 scanf("%d",&p[i]); 32 if( e[ p[idx] ][ p[i] ]>=i-idx ) { 33 ans++; 34 del[i-1]=1; 35 }else idx=i-1; 36 } 37 38 printf("%d\n",m-ans); 39 for (int i=0; i<m; i++) if(!del[i]) printf("%d ",p[i]); 40 cout<<endl; 41 } 42 return 0; 43 }
UVALive - 3902
-
vjudge上的地址 https://vjudge.net/problem/UVALive-3902
- 容易想到的贪心,就是对于每个叶子节点,把服务器的复制放在尽量离他远的地方。
- 但是就算是用了上面一种贪心策略还是会有很多种放置♂方式
- 然后又贪心,从深度♂比较大的客户端开始考虑
- 代码:
1 #include <bits/stdc++.h> 2 #define nmax 1100 3 4 using namespace std; 5 int cas,k,n,ina,inb,s; 6 vector <int> g[nmax]; 7 int vis[nmax]={0},fa[nmax]={0}; 8 struct node{ 9 int d,u; 10 bool operator < (const node a){ return a.d<d; } 11 }x[nmax]; 12 13 void dfs1(int u){ //以s为根拉树,然后处理出每个点的父亲 14 for (int i=0; i<g[u].size(); i++) { 15 int v=g[u][i]; 16 if(fa[v]==0) { fa[v]=u; x[v].d=x[u].d+1; dfs1(v); } 17 } 18 } 19 20 void dfs(int f,int u,int dep){ //给某个服务器服务到的点标1 21 vis[u]=1; 22 if(dep==k) return; 23 for (int i=0; i<g[u].size(); i++) if(g[u][i]!=f) dfs(u,g[u][i],dep+1); 24 } 25 26 int main(){ 27 cin>>cas; 28 while(cas--){ 29 memset(vis,0,sizeof(vis)); 30 memset(fa,0,sizeof(fa)); 31 scanf("%d%d%d",&n,&s,&k); 32 x[s].d=0; 33 for (int i=1; i<=n; i++) { x[i].u=i; g[i].clear(); } 34 for (int i=1; i<n; i++) { 35 scanf("%d%d",&ina,&inb); 36 g[ina].push_back(inb); 37 g[inb].push_back(ina); 38 } 39 fa[s]=s; 40 dfs1(s); 41 sort(x+1,x+n+1); 42 dfs(s,s,0); 43 int ans=0; 44 for (int i=1; i<=n; i++) { 45 int u=x[i].u; 46 if( g[u].size()>1 || vis[u] ) continue; 47 int v=u; 48 for (int i=0; i<k; i++) v=fa[v]; 49 dfs(v,v,0); 50 ans++; 51 } 52 printf("%d\n",ans); 53 } 54 return 0; 55 }