[World Final2015试题选做]

World Final的题做的人太少了网上也找不到题解,蒟蒻只好挑几道水题做做啦。

A.Amalgamated Artichokes

sb题,记录一下前缀最大值就行了。

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;

int p,a,b,c,d,n;
double ans,price[1000005];

inline double calc(int k)
{
    return (double)p*(sin(a*k+b)+cos(c*k+d)+2);
}

int main()
{
    scanf("%d%d%d%d%d%d",&p,&a,&b,&c,&d,&n);
    for (int i=1;i<=n;i++)
        price[i]=calc(i);
    double mx=price[1];
    for (int i=2;i<=n;i++)
    {
        ans=max(ans,mx-price[i]);
        mx=max(mx,price[i]);
    }
    printf("%.6lf\n",ans);
    return 0;
}

C.Catering

有上下界的费用流。
首先将人拆点,加上下界为1的流量限制,从源点发出K的流量,然后可以相互转移的连边加上费用,直接跑就行了。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int N=210;
const int M=30005;
const int mod=210;
const int inf=1000000007;
int head[N],dis[N],path[N],q[N];
int list[M],next[M],flow[M],from[M],cost[M];
bool vis[N];
int n,k,A,S,T,SS,TT,cnt,ans;

inline void insert(int x,int y,int z,int w)
{
    next[++cnt]=head[x];
    head[x]=cnt;
    from[cnt]=x;
    list[cnt]=y;
    flow[cnt]=z;
    cost[cnt]=w;
}

inline bool spfa()
{
     for (int i=0;i<=TT;i++) dis[i]=inf;
     int t=0,w=1,x;
     q[1]=SS; vis[SS]=true; dis[SS]=0;
     while (t!=w)
     {
        t=(t+1)%mod;
        x=q[t];
        for (int i=head[x];i;i=next[i])
            if (flow[i]&&dis[list[i]]>dis[x]+cost[i])
            {
                dis[list[i]]=dis[x]+cost[i];
                path[list[i]]=i;
                if (!vis[list[i]])
                {
                    vis[list[i]]=true;
                    w=(w+1)%mod;
                    q[w]=list[i];
                }
            }
        vis[x]=false;
     }
     return dis[TT]!=inf;
}

inline void mcf()
{
    int x=inf;
    for (int i=path[TT];i;i=path[from[i]]) x=min(x,flow[i]);
    for (int i=path[TT];i;i=path[from[i]])
        flow[i]-=x,flow[i^1]+=x,ans+=x*cost[i];
}

int main()
{
    scanf("%d%d",&n,&k);
    S=0; A=n<<1|1; T=A+1; SS=T+1; TT=SS+1; cnt=1;
    for (int i=0;i<n;i++)
        for (int j=1;j<=n-i;j++)
        {
            int x;
            scanf("%d",&x);
            if (!i)
                insert(A,i+j,1,x),insert(i+j,A,0,-x);
            else
                insert(i+n,i+j,1,x),insert(i+j,i+n,0,-x);
        }
    for (int i=1;i<=n;i++)
        insert(i+n,T,1,0),insert(T,i+n,0,0);
    insert(S,A,k,0); insert(A,S,0,0);
    for (int i=1;i<=n;i++) 
        insert(i,TT,1,0),insert(TT,i,0,0);
    for (int i=1;i<=n;i++)
        insert(SS,i+n,1,0),insert(i+n,SS,0,0);
    insert(T,S,inf,0); insert(S,T,0,0);
    while (spfa()) mcf();
    cout << ans << endl;
    return 0;
}

F.Keyboarding

fi,j,k 表示走到点 (i,j) 已经打了 k 个的最小步数,然后BFS就行了。
注意可以在一个点打多次,开始没看到WA了一发。

#include<iostream>
#include<cstdio>
#include<queue>
#include<map>
#include<cstdlib>
#include<cstring>
#define pii pair<int,int>
using namespace std;

const int N=51;
const int L=10005;
const int INF=1000000007;
const int dx[4]={-1,0,0,1};
const int dy[4]={0,1,-1,0};
int n,m,len,ans=INF;
pii next[N][N][4];
bool vis[N][N][L];
char s[N][N],T[L];
struct node
{
    int x,y,step,total;
};

inline bool in(int x,int y)
{
    return x>=1&&x<=n&&y>=1&&y<=m;
}

inline void pre()
{
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            for (int k=0;k<4;k++)
            {
                int x=i+dx[k],y=j+dy[k];
                while (s[x][y]==s[i][j]&&in(x,y)) x=x+dx[k],y=y+dy[k];
                next[i][j][k]=make_pair(x,y);
            }
}

inline void BFS()
{
    queue<node> q;
    if (s[1][1]==T[1]) q.push((node){1,1,1,1}),vis[1][1][1]=true;
    else q.push((node){1,1,0,0}),vis[1][1][0]=true;
    while (!q.empty())
    {
        node now=q.front(); q.pop();
//      cout << now.x << " " << now.y << " " << now.step << " " << now.total << endl;
//      system("pause");
        if (s[now.x][now.y]==T[now.step+1]&&!vis[now.x][now.y][now.step+1])
        {
            vis[now.x][now.y][now.step+1]=true;
            q.push((node){now.x,now.y,now.step+1,now.total+1});
        }
        for (int k=0;k<4;k++)
        {
            pii nxt=next[now.x][now.y][k];
            if (!in(nxt.first,nxt.second)) continue;
            int x=nxt.first,y=nxt.second;
            if (T[now.step+1]==s[x][y]) 
            {
                if (vis[x][y][now.step+1]) continue;
                vis[x][y][now.step+1]=true;
                q.push((node){x,y,now.step+1,now.total+2});
                if (now.step+1==len) ans=min(ans,now.total+2);
            }
            else
            {
                if (vis[x][y][now.step]) continue;
                vis[x][y][now.step]=true;
                q.push((node){x,y,now.step,now.total+1});
            }
        }
    }
}           

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

    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        scanf("%s",s[i]+1);
    scanf("%s",T+1);
    len=strlen(T+1)+1;
    T[len]='*';
    pre();
    BFS();
    cout << ans << endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值