这场是我有史以来第一次抢到全场FB,敲开森滴^_^
Ranklist
Pro.A Salty Fish
foj2253题目链接
最大子序列和的变形,注意题干中的“至少翻转一只咸鱼”
#include
#include
using namespace std;
int main()
{
int n,i,x,a[100005],cnt,sum,mx;
while(~scanf("%d",&n)){
for(cnt=0,i=1;i<=n;i++){
scanf("%d",&x),cnt+=x; //cnt记录已经成功翻身的咸鱼数
a[i]=x?-1:1; //a数组记录的是将会对cnt产生的影响
}
sum=0;
mx=-1; //至少翻一条,所以mx的最小值是-1(当然也可以写cnt==n的特判continue)
for(i=1;i<=n;i++){ //最大子序列和
sum+=a[i];
if(mxif(sum<0) sum=0;
}
printf("%d\n",cnt+mx);
}
}
Pro.B 英语考试
foj2254题目链接
//比赛的时候一看是字符串题,就只能联想到字典树,kmp,马拉车,AC自动机,实在没啥想法就弃了
赛后听说是最小生成树(最短路也能做)
把每个单词都看作点,两点间的距离即汉明距离*w
引入一个点(可以想象为是下标为0的点,代码中做了些许简化),向另外n个点各连一条权值为m的边
稠密图用prim
#include
#include
#include
using namespace std;
#define N 1005
#define inf 0x3f3f3f3f
#define ms(x) memset(x,0,sizeof(x))
char s[N][15];
int mp[N][N],vs[N],dis[N],n,m;
int prim()
{
int i,j,k,tmp,ret=0;
for(i=1;i<=n;i++) vs[i]=0,dis[i]=m;
for(i=1;i<=n;i++){
for(tmp=inf,j=1;j<=n;j++)if(!vs[j]&&tmp>dis[j]) tmp=dis[j],k=j;
ret+=tmp,vs[k]=1;
for(j=1;j<=n;j++)if(!vs[j]) dis[j]=min(dis[j],mp[k][j]);
}
return ret;
}
int main()
{
int w,i,j,k,tmp;
while(~scanf("%d%d%d",&n,&m,&w)){
for(i=1;i<=n;i++){
scanf("%s",s[i]);
for(j=1;jfor(tmp=0,k=0;kif(s[i][k]!=s[j][k]) tmp++;
mp[i][j]=mp[j][i]=tmp*w;
}
}
printf("%d\n",prim());
}
}
Pro.D 迷宫
foj2256题目链接
层序遍历+搜一遍该点的祖先找到最小时间
#include
#include
#include
using namespace std;
#define N 100005
vector<int>V[N];
queue<int>Q;
__int64 ans[N],d[N],w[N];
int main()
{
int n,f[N],i,p,u,v,sz;
while(~scanf("%d",&n)){
for(i=1;i<=n;i++) scanf("%I64d",&d[i]),f[i]=i,V[i].clear();
for(i=2;i<=n;i++) scanf("%d%I64d",&p,&w[i]),f[i]=p,V[p].push_back(i);
Q.push(1);
while(!Q.empty()){
u=Q.front(),Q.pop();
sz=V[u].size();
for(i=0;iwhile(p!=f[p]) p=f[p],ans[v]=min(ans[v],ans[p]+d[p]);
}
}
for(i=1;i<=n;i++) printf("%I64d ",ans[i]);
puts("");
}
}
Pro.E Saya的小熊饼干
foj2257题目链接
(100分算法?):
考虑到期望的独立性,答案等于每个格子在k次操作中被粉刷过的概率之和
对于一个格子(i,j),设它一次就被刷到的概率为p,则它在k次中被至少刷到一次的概率为1-(1-p)^k
如何计算p呢?
由于两维是独立的,分开计算后根据乘法原理乘起来即可,p=px*py
那么只需要考虑一维的情况:
长度为n的序列中i一次就被刷到的概率=1-i一次都不被刷到的概率=1-((i-1)(i-1)+(n-i)(n-i))/n/n
注:
分母中n方表示n中任取两个点(可以是同一个点)
分子中(i-1)(i-1)表示两点都在i左侧,(n-i)(n-i)表示两点都在i右侧
这题与hdoj5245几乎完全一样
#include
#include
double cal(int i,int n)
{
return 1-1.0*((i-1)*(i-1)+(n-i)*(n-i))/n/n;
}
int main()
{
int k,n,m,i,j;
while(~scanf("%d%d%d",&k,&n,&m)){
double ans=0,p;
for(i=1;i<=n;i++)for(j=1;j<=m;j++)
p=cal(i,n)*cal(j,m),ans+=1-pow(1-p,k);
printf("%.0f\n",ans); //四舍五入,(int)是截尾取整
}
}
Pro.F 奖励
foj2258题目链接
#include
int main()
{
int n,cnt,a,b,c;
while(~scanf("%d",&n)){
cnt=0;
while(n--){
scanf("%d%d%d",&a,&b,&c);
if(a<60||b<60||c<60) continue;
if(a+b+c>=240) cnt++;
}
printf("%d\n",cnt);
}
}
Pro.H Card Game
foj2260题目链接
用pre和nxt数组模拟链表,用队列模拟删的过程,复杂度O(n)
#include
#include
#include
using namespace std;
#define N 1000005
int a[N],pre[N],nxt[N],vs[N];
typedef pair<int,int>P;
queueQ;
int main()
{
int n,i,ans,u,v;
while(~scanf("%d",&n)){
for(i=1;i<=n;i++){
scanf("%d",&a[i]),pre[i]=i-1,nxt[i]=i+1,vs[i]=0;
if(a[i]1]) Q.push(P(i,1)),vs[i]=1;
}
ans=0;
while(!Q.empty()){
P p=Q.front();Q.pop();
u=p.first,v=p.second;
ans=max(ans,v);
nxt[pre[u]]=nxt[u];
pre[nxt[u]]=pre[u];
if(pre[u]&&nxt[u]!=n+1&&!vs[nxt[u]]&&a[nxt[u]]1)),vs[nxt[u]]=1;
}
printf("%d\n",ans);
for(i=1;i!=n+1;i=nxt[i]) printf("%d%c",a[i],nxt[i]==n+1?'\n':' ');
}
}
Pro.I 浪里个浪
foj2261题目链接
最短路,与hdoj2066类似,但数据更强
建立一个超级起点(下标为0),超级终点(下标为n+1)
超级起点向每个起点连一条权值为0的边,每个终点像超级终点连一条权值为0的边,跑单源最短路即可(代码中用的是spfa)
#include
#include
#include
using namespace std;
#define N 100005
const int inf=0x7ffffff;
struct edge
{
int to,w,nxt;
}e[N*3];
int head[N],t,vs[N],dis[N];
void add(int i,int j,int w)
{
e[t].to=j;
e[t].w=w;
e[t].nxt=head[i];
head[i]=t++;
}
void spfa(int s,int n)
{
int i,u,v;
queue<int>Q;
for(i=0;i<=n;i++) dis[i]=inf,vs[i]=0;
Q.push(s);
dis[s]=0;
while(!Q.empty()){
u=Q.front(),Q.pop();
vs[u]=0;
for(i=head[u];i!=-1;i=e[i].nxt){
v=e[i].to;
if(dis[v]>dis[u]+e[i].w){
dis[v]=dis[u]+e[i].w;
if(!vs[v]) vs[v]=1,Q.push(v);
}
}
}
}
int main()
{
int n,m,i,u,v,w,x;
while(~scanf("%d%d",&n,&m)){
t=0;
memset(head,-1,sizeof(head));
while(m--) scanf("%d%d%d",&u,&v,&w),add(u,v,w);
scanf("%d",&m);
while(m--) scanf("%d",&x),add(0,x,0);
scanf("%d",&m);
while(m--) scanf("%d",&x),add(x,n+1,0);
spfa(0,n+1);
printf("%d\n",dis[n+1]);
}
}