• 辣些数据结构的思维题(思维题好难一个都不会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
      ",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
      ",ans);
      61     }
      62     return 0;
      63 }
      ^3^

    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
      ");
      28         printf("%d %d
      ",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
      ",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 }
      嘤雄不朽+1s

    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
      ",ans);
      53     }
      54     return 0;
      55 }
      嘤年早逝
  • 相关阅读:
    进制
    变量
    cmd命令和快捷键
    面向对象和面向过程
    iterations 快捷键
    SQL语句分类和语法
    MySQL语法规范
    Web-Scale-IT 到底是啥?
    安全的应用程序开发和应用程序安全防御
    如何像后端一样写前端代码?
  • 原文地址:https://www.cnblogs.com/jiecaoer/p/11332827.html
Copyright © 2020-2023  润新知