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 ",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 ",ans); 39 return 0; 40 } 41 42 int Aptal=Presist(); 43 int main(int argc,char**argv){;}
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 ",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 ",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 ",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){;}
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 ",f[1][0]); 57 return 0; 58 } 59 60 int Aptal=Presist(); 61 int main(int argc,char**argv){;}