所以我又回來了,這次是test7。
(test1,test2,test3,集體失蹤,敬請期待(攤手))
嗯,喜大普奔。
上題。
1.1807
題目描述
給出一個由數字(‘0’-‘9’)構成的字符串。我們說一個子序列是好的,如果他的每一位都是 1、8、0、7 ,並且這四個數字按照這種順序出現,且每個數字都出現至少一次(111888888880000007 是好的,而 1087 不是)。請求出最大的好的子序列的長度。
輸入格式
輸入唯一一行一個字符串。
輸出格式
一行一個整數表示答案。
樣例數據
輸入
1800777700088888000777
輸出
13
備註
【數據範圍】
對 30% 的輸入數據 :字符串長度≤100 ;
對 100% 的輸入數據 :字符串長度≤1000000 。
第一次看到題的時候糾結了好久,感覺怎麼做都考慮不完全。
最後決定把‘1’賦爲1,‘8’賦爲2,‘0’賦爲3,‘7’賦爲4。
然後用了最長不下降子序列。
但是bug簡直太多了。
首先不僅2大於1,3也大於1,4也是。
然後又不能保證1、2、3、4四個數字都會出現。
於是又在不同情況下做了分類討論,討論出來3kb。
然後……然後只有10分。
這是一個黃少天聽了沉默,韓文清看了流淚的故事。
好了,代碼和正解。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;
int len,ans;
int a[1000005],f[1000005][5];
char s[1000005];
int main()
{
//freopen("1807.in","r",stdin);
//freopen("1807.out","w",stdout);
memset(f,128,sizeof(f));
scanf("%s",s+1);
len=strlen(s+1);
f[0][0]=0;
for(int i=1;i<=len;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(s[i]=='1')
f[i][1]=max(f[i][1],f[i-1][0])+1;
if(s[i]=='8')
f[i][2]=max(f[i][2],f[i-1][1])+1;
if(s[i]=='0')
f[i][3]=max(f[i][3],f[i-1][2])+1;
if(s[i]=='7')
f[i][4]=max(f[i][4],f[i-1][3])+1;
}
cout<<max(0,f[len][4])<<endl;
return 0;
}
開一個二維數組(其實一維也可以,爲了敘述方便)f[i][j],i表示現在已經取了前面i位,用到了第j個數字(即1、8、0、7),最後輸出f[n][4]。
至於動態轉移方程,e.g.對於‘8’來說,只有前面是‘1’或是‘8’時纔有更新的資格,否則沒有。
2.Minimum
題目描述
給出一幅由 n 個點 m 條邊構成的無向帶權圖。
其中有些點是黑點,另外點是白點。
現在每個白點都要與他距離最近的黑點通過最短路連接(如果有很多個,可以選取其中任意一個),我們想要使得花費的代價最小。請問這個最小代價是多少?
注意:最後選出的邊保證每個白點到黑點的距離任然是最短距離。
輸入格式
第一行兩個整數 n,m ;
第二行 n 個整數,0 表示白點,1 表示黑點;
接下來 m 行,每行三個整數 x,y,z ,表示一條連接 x 和 y 點,權值爲 z 的邊。
輸出格式
如果無解,輸出“impossible”,否則,輸出最小代價。
樣例數據
輸入
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 。
嗯很好,其實第一遍看的時候根本沒有理解題目的意思。
好吧最後還是懂了,就是找一個白點到周圍黑點的最短路,若有多個全部相加。(然而懂了也並沒有什麼用)【滑稽】
直接說說考完後拿到的正解吧。
整個解題過程分爲兩塊,但前提是還要證明兩條規律。
1.最短路上的所有點必連通,且一條最短路上只有最末點是黑點,其餘皆爲白點。
2.每個點連在最短路上都只連一次,即一個白點到黑點的最短路只有一條。
所以整個問題就分爲先用各種算法(喜歡就好)求最短路,然後再建最小生成樹,注意能連通的儘量都要連通。
具體做法可以取一個超級點S,在S與每個黑點之間連權值爲0的邊(可以理解爲把所有的黑點都變成起點),先處理從S出發到每個點的最短距離,獲得最短路徑圖一張。這樣以後我們需要取權值最小的邊的集合使這幅圖連通,此時用到Kruskal算法求最小生成樹。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#define S 0
using namespace std;
struct node
{
int next;
int to;
int w;
}bian[3000003];
struct gl
{
int x;
int y;
int w;
}e[3000003];
int n,m,tot,cnt,inf,cont;
long long ans,dis[100010];
int first[100010],b[3000003],c[100010];
bool exist[100010];
inline void create(int x,int y,int z)
{
tot++;
bian[tot].next=first[x];
first[x]=tot;
bian[tot].to=y;
bian[tot].w=z;
}
inline void czh(int x,int y,int z)
{
e[++cnt].x=x;
e[cnt].y=y;
e[cnt].w=z;
}
inline void zql(int s)
{
memset(dis,40,sizeof(dis));
inf=dis[0];
int head=0,tail=1;
dis[s]=0;
b[1]=s;
exist[s]=true;
while(head^tail)
{
if(++head==3000000)
head=1;
int now=b[head];
exist[now]=false;
for(int i=first[now];i;i=bian[i].next)
{
int next=bian[i].to;
if(dis[next]>dis[now]+bian[i].w)
{
dis[next]=dis[now]+bian[i].w;
if(!exist[next])
{
exist[next]=true;
if(++tail==3000000)
tail=1;
b[tail]=next;
}
}
}
}
}
inline int find(int x)
{
return x==c[x]?x:c[x]=find(c[x]);
}
inline bool comp(gl a,gl b)
{
return a.w<b.w;
}
int main()
{
//freopen("minimum.in","r",stdin);
//freopen("minimum.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
int u;
cin>>u;
if(u==1)
create(S,i,0);
}
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
create(x,y,z);
create(y,x,z);
}
zql(S);
for(int i=1;i<=n;i++)
if(dis[i]==inf)
{
cout<<"impossible"<<endl;
return 0;
}
for(int i=1;i<=n;i++)
for(int j=first[i];j;j=bian[j].next)
{
if(dis[bian[j].to]+bian[j].w==dis[i])
czh(bian[j].to,i,bian[j].w);
}
sort(e+1,e+1+cnt,comp);
for(int i=1;i<=n;i++)
c[i]=i;
for(int i=1;i<=cnt;i++)
{
int u=e[i].x,v=e[i].y,w=e[i].w;
int pu=find(u),pv=find(v);
if(pu!=pv)
{
c[pu]=pv;
ans+=w;
if(++cont==n-1)
break;
}
}
if(ans)
cout<<ans<<endl;
else
cout<<"impossible"<<endl;
return 0;
}
3.(假裝這裏有題的樣子)
好吧其實是真有的,但是莫比烏斯函數什麼的數論那一坨還沒有過多涉獵,基本上看着題解也是一臉大寫的懵逼,所以就裝作什麼都不知道的樣子,假裝只有兩道題,嗯咳。。。。。
來自2017.7.17
——我認爲return 0,是一個時代的終結。