叉叉


题目名称



叉叉



程序文件名



cross



输入文件名



cross.in



输出文件名



cross.out



每个测试点时限



1秒



内存限制



128MB



测试点数目



10



每个测试点分值



10



是否有部分分





试题类型



传统


 

题目描述

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

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

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

输入格式

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

输出格式

一个整数,表示答案。

样例输入

abaazooabz

样例输出

3

数据范围

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

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

 思路:模拟



#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
char s[100010];
int len,ans;
int pos[28],vis[28];
int main(){
freopen("cross.in","r",stdin);
freopen("cross.out","w",stdout);
scanf("%s",s+1);
len=strlen(s+1);
for(int i=1;i<=26;i++){
int flag=0,num=0;
memset(vis,0,sizeof(vis));
memset(pos,-1,sizeof(pos));
for(int j=1;j<=len;j++){
int x=s[j]-'a'+1;
if(s[j]-'a'+1==i&&flag){ ans+=num;flag=0;num=0; }
else if(s[j]-'a'+1==i&&flag==0){ flag=j; }
else if(flag){
if(vis[s[j]-'a'+1]){
vis[s[j]-'a'+1]=0;
if(pos[s[j]-'a'+1]<flag){ num++;pos[s[j]-'a'+1]=-1; }
else{ num--;pos[s[j]-'a'+1]=-1; }
}
else{ num++;vis[s[j]-'a'+1]=1;pos[s[j]-'a'+1]=j; }
}
else if(flag==0){
if(vis[s[j]-'a'+1]) vis[s[j]-'a'+1]=0,pos[s[j]-'a'+1]=-1;
else vis[s[j]-'a'+1]=1,pos[s[j]-'a'+1]=j;
}
}
}
cout<<ans/2;
}
/*
aaaaaaaa 0
abababab 2
fgshahafgs 4
agafsdgfsd 7
abaazooabz 3
fgsgsfsdaads 1
abcdacdbcabdacbd 9
absbsbsbsddaskaksa 4
abaaaaaaaabbbbbbbbab 3
ghdgahsgdhasgdhasghdgasgdashgdhasgdgshs 37
*/


测试 10.23_#include

思路:


测试 10.23_#include_02测试 10.23_i++_03


#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 20010
using namespace std;
int n,m,q,k;
int tot,tot1;
int ans=0x7f7f7f7f;
int dis[MAXN],vis[MAXN];
int dis1[MAXN],vis1[MAXN];
int to[MAXN],net[MAXN],cap[MAXN],head[MAXN];
int to1[MAXN],net1[MAXN],cap1[MAXN],head1[MAXN];
struct nond{
int x,y,z;
}edge[MAXN];
void add(int u,int v,int w){
to[++tot]=v;cap[tot]=w;net[tot]=head[u];head[u]=tot;
}
void add1(int u,int v,int w){
to1[++tot1]=v;cap1[tot1]=w;net1[tot1]=head1[u];head1[u]=tot1;
}
void spfa(int s){
queue<int>que;
memset(vis,0,sizeof(vis));
memset(dis,0x7f,sizeof(dis));
que.push(s);
dis[s]=0;vis[s]=1;
while(!que.empty()){
int now=que.front();
que.pop();
vis[now]=0;
for(int i=head[now];i;i=net[i])
if(dis[to[i]]>dis[now]+cap[i]){
dis[to[i]]=dis[now]+cap[i];
if(!vis[to[i]]){
vis[to[i]]=1;
que.push(to[i]);
}
}
}
}
void spfaa(int s){
queue<int>qu;
memset(vis1,0,sizeof(vis1));
memset(dis1,0x7f,sizeof(dis1));
qu.push(s);
dis1[s]=0;vis1[s]=1;
while(!qu.empty()){
int now=qu.front();
qu.pop();
vis1[now]=0;
for(int i=head1[now];i;i=net1[i])
if(dis1[to1[i]]>dis1[now]+cap1[i]){
dis1[to1[i]]=dis1[now]+cap1[i];
if(!vis1[to1[i]]){
vis1[to1[i]]=1;
qu.push(to1[i]);
}
}
}
}
int main(){
freopen("move.in","r",stdin);
freopen("move.out","w",stdout);
scanf("%d%d%d%d",&n,&m,&q,&k);
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add1(v,u,w);
}
for(int i=1;i<=q;i++)
scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].z);
if(k==0){
spfa(1);
if(dis[n]==2139062143){ cout<<"-1"; return 0; }
else cout<<dis[n];
}
else if(k==1){
spfa(1);
spfaa(n);
ans=dis[n];
if(dis[n]==2139062143){ cout<<"-1"; return 0; }
for(int i=1;i<=q;i++){
if(dis[edge[i].x]==2139062143) continue;
if(dis[edge[i].y]==2139062143) continue;
ans=min(ans,dis[edge[i].x]+dis1[edge[i].y]+edge[i].z);
}
cout<<ans;
}
else if(k>=q){
for(int i=1;i<=q;i++)
add(edge[i].x,edge[i].y,edge[i].z);
spfa(1);
if(dis[n]==2139062143){ cout<<"-1"; return 0; }
cout<<dis[n];
}
else{
spfa(1);
cout<<dis[n]-100;
}
}
/*
5 5 2 1
1 2 1
1 3 2
2 4 2
3 4 3
4 5 4
1 4 1
2 5 1
*/

80分暴力

测试 10.23_#include_02测试 10.23_i++_03


#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 20010
using namespace std;
int n,m,q,k;
int tot,tot1;
int ans=0x7f7f7f7f;
int dis[MAXN],vis[MAXN];
int dis1[MAXN],vis1[MAXN];
int to[MAXN],net[MAXN],cap[MAXN],head[MAXN];
int to1[MAXN],net1[MAXN],cap1[MAXN],head1[MAXN];
struct nond{
int x,y,z;
}edge[MAXN];
void add(int u,int v,int w){
to[++tot]=v;cap[tot]=w;net[tot]=head[u];head[u]=tot;
}
void add1(int u,int v,int w){
to1[++tot1]=v;cap1[tot1]=w;net1[tot1]=head1[u];head1[u]=tot1;
}
void spfa(int s){
queue<int>que;
memset(vis,0,sizeof(vis));
memset(dis,0x7f,sizeof(dis));
que.push(s);
dis[s]=0;vis[s]=1;
while(!que.empty()){
int now=que.front();
que.pop();
vis[now]=0;
for(int i=head[now];i;i=net[i])
if(dis[to[i]]>dis[now]+cap[i]){
dis[to[i]]=dis[now]+cap[i];
if(!vis[to[i]]){
vis[to[i]]=1;
que.push(to[i]);
}
}
}
}
void spfaa(int s){
queue<int>qu;
memset(vis1,0,sizeof(vis1));
memset(dis1,0x7f,sizeof(dis1));
qu.push(s);
dis1[s]=0;vis1[s]=1;
while(!qu.empty()){
int now=qu.front();
qu.pop();
vis1[now]=0;
for(int i=head1[now];i;i=net1[i])
if(dis1[to1[i]]>dis1[now]+cap1[i]){
dis1[to1[i]]=dis1[now]+cap1[i];
if(!vis1[to1[i]]){
vis1[to1[i]]=1;
qu.push(to1[i]);
}
}
}
}
int main(){
freopen("move.in","r",stdin);
freopen("move.out","w",stdout);
scanf("%d%d%d%d",&n,&m,&q,&k);
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add1(v,u,w);
}
for(int i=1;i<=q;i++)
scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].z);
if(k==0){
spfa(1);
if(dis[n]==2139062143){ cout<<"-1"; return 0; }
else cout<<dis[n];
}
else if(k==1){
spfa(1);
spfaa(n);
ans=dis[n];
if(dis[n]==2139062143){ cout<<"-1"; return 0; }
for(int i=1;i<=q;i++){
if(dis[edge[i].x]==2139062143) continue;
if(dis[edge[i].y]==2139062143) continue;
ans=min(ans,dis[edge[i].x]+dis1[edge[i].y]+edge[i].z);
}
cout<<ans;
}
else{
for(int i=1;i<=q;i++)
add(edge[i].x,edge[i].y,edge[i].z);
spfa(1);
if(dis[n]==2139062143){ cout<<"-1"; return 0; }
cout<<dis[n];
}
}
/*
5 5 2 1
1 2 1
1 3 2
2 4 2
3 4 3
4 5 4
1 4 1
2 5 1
*/

非正解卡过思路

正解:dp


测试 10.23_#include_02测试 10.23_i++_03


#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <queue>
#include <vector>

using namespace std;

namespace Solve
{
typedef pair<int,int> Node;
const int MAXN = 500 + 10, MAXM = 2000 + 10, INF = 0x7fffffff/2;
int n, m, q, k;
int nodes[MAXN][MAXN], nop;
int head[MAXN*MAXN], next[MAXN*MAXM*2], to[MAXN*MAXM*2], w[MAXN*MAXM*2], op;
int dis[MAXN*MAXN];

void build(int a, int b, int x)
{
next[++op]=head[a];head[a]=op;to[op]=b;w[op]=x;
}
int dijkstra(int s, int t, int n)
{
priority_queue<Node, vector<Node>, greater<Node> > que;

for(int i=1;i<=n;i++) dis[i] = INF;
dis[s] = 0;
que.push(Node(dis[s], s));
while(!que.empty())
{
Node u = que.top(); que.pop();
if (dis[u.second] != u.first) continue;
for(int pos=head[u.second]; pos; pos=next[pos])
{
if (u.first + w[pos] < dis[to[pos]])
{
dis[to[pos]] = u.first + w[pos];
que.push(Node(dis[to[pos]], to[pos]));
}
}
}

return dis[t] == INF ? -1 : dis[t];
}
void solve()
{
scanf("%d%d%d%d", &n, &m, &q, &k);
k = min(k, n);

nop = 0;
for(int i=0;i<=k;i++)
for(int u=1;u<=n;u++)
nodes[i][u] = ++nop;

for(int i=1;i<=m;i++)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
for(int j=0;j<=k;j++)
build(nodes[j][u], nodes[j][v], w);
}

for(int i=1;i<=q;i++)
{
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
for(int j=0;j<k;j++)
build(nodes[j][x], nodes[j+1][y], z);
}

for(int i=0;i<k;i++)
build(nodes[i][n], nodes[i+1][n], 0);

cout << dijkstra(nodes[0][1], nodes[k][n], nop) << endl;
}
}

int main()
{
freopen("move.in", "r", stdin);
freopen("move.out", "w", stdout);

Solve::solve();

return 0;
}

View Code

 

测试 10.23_i++_08

测试 10.23_模拟_09

测试 10.23_模拟_10

思路:树形DP

设dp[i][j]表示在i的子树中j所在的联通块的大小 为dp[i][j],其他联通块大小均符合要求的删边方案数

然后

求助大佬翻译一下题解:



考虑用树形dp来解决这道问题。  
设f[i][j] 表示在i的子树中j所在的连通块大小为f[i][j],且其他连通块大小均符合要求的删边方案数
对于每个点??我们一棵一棵地将其子树加进来,设新加入子树的根为??
若删除??与??之间的边,则用??[??][??] * sum(??[??][??]) s \in [k,n] 去更新??[??][??]
若不删??与??之间的边,则枚举??所在连通块的大小??,并更新??[??][??+??]
时间复杂度 O(n^3) ?
考虑一个优化:每次新加一颗子树时,??只需枚举到前面已经加进来的子树大小之和,??也只需枚举到新子树的大小
这只是一个常数优化?其实每个点对相当于只在??????处被算了一次
故优化后的时间复杂度是O(n^2)的,本题得以解决。



#include<cstdio>
#include<cstdlib>
#define MAXN 5555
#define mod 786433
using namespace std;
int n,K,tot;
long long f[MAXN][MAXN];
int to[MAXN*2],net[MAXN*2],head[MAXN];
long long size[MAXN],g[MAXN],cnt[MAXN];
void add(int u,int v){
to[++tot]=v;net[tot]=head[u];head[u]=tot;
to[++tot]=u;net[tot]=head[v];head[v]=tot;
}
void dfs(int now,int fa){
size[now]++;
f[now][1]=1;
for(int i=head[now];i;i=net[i])
if(to[i]!=fa){
dfs(to[i],now);
for(int j=1;j<=size[now]+size[to[i]];j++) g[j]=0;
for(int j=1;j<=size[now];j++) g[j]=cnt[to[i]]*f[now][j]%mod;
for(int j=1;j<=size[now];j++)
for(int k=1;k<=size[to[i]];k++) g[j+k]=(g[j+k]+f[now][j]*f[to[i]][k]%mod)%mod;
for(int j=1;j<=size[now]+size[to[i]];j++) f[now][j]=g[j];
size[now]+=size[to[i]];
}
for(int i=K;i<=size[now];i++) cnt[now]=(cnt[now]+f[now][i])%mod;
return ;
}
int main(){
freopen("cut.in","r",stdin);
freopen("cut.out","w",stdout);
scanf("%d %d",&n,&K);
for (int i=1;i<n;i++){
int u,v;
scanf("%d %d",&u,&v);
add(u,v);
}
dfs(1,1);
printf("%d\n",cnt[1]);
return 0;
}


 


细雨斜风作晓寒。淡烟疏柳媚晴滩。入淮清洛渐漫漫。 雪沫乳花浮午盏,蓼茸蒿笋试春盘。人间有味是清欢。