给出一个由数字(‘0’-‘9’)构成的字符串。我们说一个子序列是好的,如果他的每一位都是 1、8、0、7 ,并且这四个数字按照这种顺序出现,且每个数字都出现至少一次(111888888880000007 是好的,而 1087 不是)。请求出最大的好的子序列的长度。
T1
题目描述
输入格式
输入唯一一行一个字符串。
输出格式
一行一个整数表示答案。
样例数据 1
输入
1800777700088888000777
输出
13
备注
【数据范围】
对 30% 的输入数据 :字符串长度≤100 ;
对 100% 的输入数据 :字符串长度≤1000000
解析:
对于30%的数据,枚举最后一个1,最后一个0,最后一个8的位置,分别搜索第一段,第二段,第三段和最后一段各有几个1、8、0、7,用和来更新最大值。复杂度O(n^4)
对于100%的数据,动态规划,f[i][j]表示前i位,当前用到了第j个数字(分别指1、8、0、7),最后f[n][4]即为答案。复杂度O(n)
代码如下:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <cctype>
#include <ctime>
#include <queue>
#include <vector>
#include <sstream>
using namespace std;
int n;
int f[1000010][5];
char num[1000010];
int get_int()
{
int x=0,f=1;
char c;
for(c=getchar();(c<'0'||c>'9')&&(c!='-');c=getchar());
if(c=='-') {f=-1; c=getchar();}
for(;c>='0'&&c<='9';c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
int main()
{
// freopen("1807.in","r",stdin);
// freopen("1807.out","w",stdout);
memset(f,128,sizeof(f));
scanf("%s",num+1);
n=strlen(num+1);
f[0][0]=0;
for(int i=1;i<=n;i++)
{
f[i][0]=f[i-1][0];
f[i][1]=f[i-1][1];
f[i][2]=f[i-1][2];
f[i][3]=f[i-1][3];
f[i][4]=f[i-1][4];
if(num[i]=='1') f[i][1]=max(f[i][1],f[i-1][0])+1;
if(num[i]=='8') f[i][2]=max(f[i][2],f[i-1][1])+1;
if(num[i]=='0') f[i][3]=max(f[i][3],f[i-1][2])+1;
if(num[i]=='7') f[i][4]=max(f[i][4],f[i-1][3])+1;
}
cout<<max(f[n][4],0)<<endl;
return 0;
}
T2
题目描述
给出一幅由 n 个点 m 条边构成的无向带权图。
其中有些点是黑点,另外点是白点。
现在每个白点都要与他距离最近的黑点通过最短路连接(如果有很多个,可以选取其中任意一个),我们想要使得花费的代价最小。请问这个最小代价是多少?
注意:最后选出的边保证每个白点到黑点的距离任然是最短距离。
输入格式
第一行两个整数 n,m ;
第二行 n 个整数,0 表示白点,1 表示黑点;
接下来 m 行,每行三个整数 x,y,z ,表示一条连接 x 和 y 点,权值为 z 的边。
输出格式
如果无解,输出“impossible”,否则,输出最小代价。
样例数据 1
输入
5 7
0 1 0 1 0
1 2 11
1 3 1
1 5 17
2 3 1
3 5 18
4 5 3
2 4 5
输出
5
备注
【样例说明】
选 2、4、6 三条边。
【数据范围】
对 30% 的输入数据 :1≤n≤10,1≤m≤20;
对 100% 的输入数据 :1≤n≤100000,1≤m≤200000,1≤z≤1000000000 。
解析:
对于30%的数据,枚举每条边的选取情况,暴力判断。
对于100%的数据,添加一个超级点,使得它与每个黑点相连且权值为0,用SPFA处理从S出发的最短路,问题就变成了选取权值最小的边的集合,使这幅图连通,于是就可以用最小生成树的Kruskal。
代码如下:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <cctype>
#include <ctime>
#include <queue>
#include <vector>
#include <sstream>
using namespace std;
const int Max=1000100;
long long n,m,ans;
struct spfa{int to,next,len;};
spfa bian[Max];
long long s1,head,tail;
long long first[Max],p[Max],dis[Max];
bool exist[Max];
struct kruskal{int x,y,z;};
kruskal size[Max];
int father[Max];
long long s2;
int get_int()
{
int x=0,f=1;
char c;
for(c=getchar();(c<'0'||c>'9')&&(c!='-');c=getchar());
if(c=='-') {f=-1; c=getchar();}
for(;c>='0'&&c<='9';c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
void clear()
{
s1=0;s2=0;
memset(bian,0,sizeof(bian));
memset(first,0,sizeof(first));
memset(p,0,sizeof(p));
memset(dis,127,sizeof(dis));
memset(father,0,sizeof(father));
}
int getfather(long long v)
{
if(father[v]==v) return v;
father[v]=getfather(father[v]);
return father[v];
}
void merge(long long x,long long y)
{
int i=getfather(x);
int j=getfather(y);
if(i!=j) father[i]=j;
}
void tree()
{
for(long long i=1;i<=n;i++) father[i]=i;
for(long long i=1;i<=s2;i++)
{
if(getfather(size[i].x)!=getfather(size[i].y))
{
ans+=size[i].z;
merge(size[i].x,size[i].y);
}
}
}
bool comp(const kruskal &a,const kruskal &b)
{
return a.z<b.z;
}
void search(int x)
{
for(long long u=first[x];u;u=bian[u].next)
if(dis[x]+bian[u].len==dis[bian[u].to])
{
search(bian[u].to);
size[++s2].x=x;
size[s2].y=bian[u].to;
size[s2].z=bian[u].len;
}
}
void SPFA()
{
memset(exist,false,sizeof(exist));
p[1]=0;
dis[0]=0;
exist[0]=true;
head=0;
tail=1;
while(head<tail)
{
head++;
exist[p[head]]=false;
long long u=first[p[head]];
while(u!=0)
{
if(dis[p[head]]+bian[u].len<dis[bian[u].to])
{
dis[bian[u].to]=dis[p[head]]+bian[u].len;
if(exist[bian[u].to]==false)
{
tail++;
p[tail]=bian[u].to;
exist[bian[u].to]=true;
}
}
u=bian[u].next;
}
}
}
void build(long long x,long long y,long long z)
{
s1++;
bian[s1].next=first[x];
first[x]=s1;
bian[s1].to=y;
bian[s1].len=z;
}
int main()
{
//freopen("minimum.in","r",stdin);
//freopen("minimum.out","w",stdout);
while(scanf("%d%d\n",&n,&m)!=EOF)
{
clear();
for(long long i=1;i<=n;i++)
{
int x;
x=get_int();
if(x) build(0,i,0);
}
for(long long i=1;i<=m;i++)
{
int x,y,z;
x=get_int();
y=get_int();
z=get_int();
build(x,y,z);
build(y,x,z);
}
SPFA();
search(0);
sort(size+1,size+s2+1,comp);
tree();
if(ans==0) cout<<"impossible"<<endl;
else cout<<ans<<endl;
}
return 0;
}