2017-10-23学大伟业Day1

本文解析了三个算法题目,包括计算字符串中字母连线交叉数量的问题、寻找带特殊边的最短路径问题以及基于树结构的计数问题。提供了详细的解题思路与代码实现。

T1 叉叉

题目名称

叉叉

程序文件名

cross

输入文件名

cross.in

输出文件名

cross.out

每个测试点时限

1秒

内存限制

128MB

测试点数目

10

每个测试点分值

10

是否有部分分

试题类型

传统

题目描述

现在有一个字符串,每个字母出现的次数均为偶数。接下来我们把第一次出现的字母a和第二次出现的a连一条线,第三次出现的和四次出现的字母a连一条线,第五次出现的和六次出现的字母a连一条线...对其他25个字母也做同样的操作。

现在我们想知道有多少对连线交叉。交叉的定义为一个连线的端点在另外一个连线的内部,另外一个端点在外部。

下图是一个例子,共有三对连线交叉(我们连线的时候,只能从字符串上方经过)。

 

输入格式

一行一个字符串。保证字符串均由小写字母组成,且每个字母出现次数为偶数次。

 

输出格式

一个整数,表示答案。

 

样例输入

abaazooabz

 

样例输出

3

 

数据范围

 

对于30% 的数据,字符串长度不超过50。

对于100% 的数据,字符串长度不超过100,000。

 

处理出每对字符的两个位置,按左端点排序,判断是否会相交,加一个小剪枝、、、暴力做法数据水就过了。。

 1 #include <algorithm>
 2 #include <cstring>
 3 #include <cstdio>
 4 
 5 const int N(100005);
 6 int cnt,n,ans;
 7 struct Node {
 8     int l,r;
 9     bool operator < (const Node&x)const
10     {
11         return l<x.l;
12     }
13 }a[N];
14 char s[N];
15 
16 int Presist()
17 {
18     freopen("cross.in","r",stdin);
19     freopen("cross.out","w",stdout);
20     scanf("%s",s+1); n=strlen(s+1);
21     cnt=1;
22     for(int k=0; k<26; ++k)
23       for(int i=1; i<=n; ++i)
24           if(s[i]-'a'==k)
25           {
26               if(a[cnt].r) a[++cnt].l=i;
27               else if(!a[cnt].l) a[cnt].l=i;
28                    else a[cnt].r=i;
29         }
30     std::sort(a+1,a+cnt+1);
31     for(int i=1; i<=cnt; ++i)
32 //        printf("%d %d\n",a[i].l,a[i].r);
33       for(int j=i+1; j<=cnt; ++j)
34       {
35           if(a[i].r<a[j].l) break;
36           ans+=(a[i].r<a[j].r);
37       }
38     printf("%d\n",ans);
39     return 0;
40 }
41 
42 int Aptal=Presist();
43 int main(int argc,char**argv){;}
AC

 

 

 

T2 跳跳虎想回家

k==0的就是普通的最短路,k==1的可以Floyd求出多源最短路,枚举每个传送通道更新最小值,

另外就是乱搞的(把传送通道全加进去跑最短路。。可能还是数据水)、、考试时数组开小了80分、

  1 #include <cstdio>
  2 #include <queue>
  3 
  4 #define min(a,b) ((a)<(b)?(a):(b))
  5 
  6 inline void read(int &x)
  7 {
  8     x=0; register char ch=getchar();
  9     for(; ch>'9'||ch<'0'; ) ch=getchar();
 10     for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0';
 11 }
 12 
 13 const int INF(0x3f3f3f);
 14 const int M(2333);
 15 const int N(505);
 16 int n,m,q,k,ans;
 17 int dis[N][N];
 18 bool vis[N];
 19 
 20 int head[N],sumedge;
 21 struct Edge {
 22     int v,next,w;
 23     Edge(int v=0,int next=0,int w=0):
 24         v(v),next(next),w(w){}
 25 }edge[M<<1];
 26 inline void ins(int u,int v,int w)
 27 {
 28     edge[++sumedge]=Edge(v,head[u],w);
 29     head[u]=sumedge; dis[u][v]=w;
 30 }
 31 
 32 struct Node {
 33     int pos,dis;
 34     bool operator < (const Node&x)const
 35     {
 36         return dis>x.dis;
 37     }
 38 }u,v;
 39 std::priority_queue<Node>que;
 40 
 41 inline void Dijkstra(int s)
 42 {
 43     for(int i=1; i<=n; ++i)
 44         dis[s][i]=INF,vis[i]=0;
 45     u.dis=dis[s][s]=0,u.pos=s;
 46     for(; !que.empty(); ) que.pop(); que.push(u);
 47     for(; !que.empty(); )
 48     {
 49         u=que.top(); que.pop();
 50         if(vis[u.pos]) continue; vis[u.pos]=1;
 51         for(int i=head[u.pos]; i; i=edge[i].next)
 52         {
 53             v.pos=edge[i].v;
 54             if(dis[s][v.pos]>dis[s][u.pos]+edge[i].w)
 55             {
 56                 dis[s][v.pos]=dis[s][u.pos]+edge[i].w;
 57                 v.dis=dis[s][v.pos]; que.push(v);
 58             }
 59         }
 60     }
 61 }
 62 
 63 struct Road {
 64     int u,v,w;
 65     Road(int u=0,int v=0,int w=0):u(u),v(v),w(w){}
 66 }road[M];
 67 
 68 inline void violence()
 69 {
 70     for(int k=1; k<=n; ++k)
 71       for(int i=1; i<=n; ++i)
 72           for(int j=1; j<=n; ++j)
 73           dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
 74     ans=dis[1][n];
 75     for(int u,w,v,i=1; i<=q; ++i)
 76     {
 77         u=road[i].u,v=road[i].v,w=road[i].w;
 78         ans=min(ans,dis[1][u]+dis[v][n]+w);
 79     }
 80     printf("%d\n",ans>=INF?(-1):ans);
 81 }
 82 
 83 inline void violence2()
 84 {
 85     for(int u,w,v,i=1; i<=q; ++i)
 86         ins(road[i].u,road[i].v,road[i].w);
 87     Dijkstra(1); printf("%d\n",dis[1][n]>=INF?(-1):dis[1][n]);
 88 }
 89 
 90 int Presist()
 91 {
 92     freopen("move.in","r",stdin);
 93     freopen("move.out","w",stdout);
 94     read(n),read(m),read(q),read(k);
 95     for(int i=1; i<=n; ++i)
 96       for(int j=1; j<=n; ++j)
 97           dis[i][j]=(i!=j)*INF;
 98     for(int u,v,w,i=1; i<=m; ++i)
 99         read(u),read(v),read(w),ins(u,v,w);
100     for(int u,v,w,i=1; i<=q; ++i)
101         read(u),read(v),read(w),road[i]=Road(u,v,w);
102     if(!k) { Dijkstra(1); printf("%d\n",dis[1][n]>=INF?(-1):dis[1][n]); return 0;}
103     else if(k==1) { violence(); return 0; }
104          else { violence2(); return 0; }
105     return 0;
106 }
107 
108 int Aptal=Presist();
109 int main(int argc,char**argv){;}
AC

 

 

 

 

T3 秀秀 和哺 噜国 ( cut )

 

f[i][j]表示以i为根,连通块大小为k的满足题目要求联通个数的方案数,f[i][0]表示以i为根的所有合法方案数

对于u的一个孩子v,f[u][j+k]+=f[u][j]*f[v][k],(乘法原理,一颗以u的孩子为根的树的贡献与其余树互不影响)

f[u][0]+=f[u][i](k<=i<=size[u])

只枚举当前 u 所在子树的大小,每当枚举到它的其中孩子时,当前 u 所在子树的大小加上它孩子为根的子树的大小。

可以理解为每一个点对只被枚举到一次。 这样可以优化到n^2

ans=f[root][0]

 1 #include <cstdio>
 2 
 3 #define min(a,b) ((a)<(b)?(a):(b))
 4 
 5 inline void read(int &x)
 6 {
 7     x=0; register char ch=getchar();
 8     for(; ch>'9'||ch<'0'; ) ch=getchar();
 9     for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0';
10 }
11 const int mod(786433);
12 const int N(5233);
13 int n,q,ans,dis[N][N];
14 int head[N],sumedge;
15 struct Edge {
16     int v,next;
17     Edge(int v=0,int next=0):v(v),next(next){}
18 }edge[N<<1];
19 inline void ins(int u,int v)
20 {
21     edge[++sumedge]=Edge(v,head[u]);
22     head[u]=sumedge,dis[u][v]=1;
23 }
24 
25 int size[N],tmp[N],f[N][N];
26 void DFS(int u,int pre)
27 {
28     size[u]=1; f[u][1]=1;
29     for(int v,i=head[u]; i; i=edge[i].next)
30     {
31         v=edge[i].v; if(v==pre) continue;
32         DFS(v,u); int tot=size[u]+size[v];
33         for(int j=1; j<=tot; ++j) tmp[j]=0;
34         for(int j=1; j<=size[u]; ++j)
35             tmp[j]=1ll*f[v][0]*f[u][j]%mod;
36         for(int j=1; j<=size[u]; ++j)
37           for(int k=1; k<=size[v]; ++k)
38               tmp[k+j]=(tmp[k+j]%mod+1ll*f[u][j]*f[v][k]%mod)%mod;
39         for(int j=1; j<=tot; ++j) f[u][j]=tmp[j];
40         size[u]+=size[v];
41     }
42     for(int i=q; i<=size[u]; ++i) f[u][0]=(f[u][0]+f[u][i])%mod;
43 }
44 
45 int Presist()
46 {
47 //    freopen("cut.in","r",stdin);
48 //    freopen("cut.out","w",stdout);
49     read(n),read(q);
50     for(int i=1; i<=n; ++i)
51       for(int j=1; j<=n; ++j)
52         dis[i][j]=(i!=j)*(n+1);
53     for(int u,v,i=1; i<n; ++i)
54         read(u),read(v),ins(u,v);
55     DFS(1,-1);
56     printf("%d\n",f[1][0]);
57     return 0;
58 }
59 
60 int Aptal=Presist();
61 int main(int argc,char**argv){;}
AC

 

转载于:https://www.cnblogs.com/Shy-key/p/7716544.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值