Benelux Algorithm Programming Contest 2014 Preliminary

题目链接

A. Choosing the Ice Cream

n个蛋糕k面的色子,要扔色子决定吃哪个,要求扔的次数最少并且每块蛋糕等可能性被选中,求最少的次数。

实际上是,每次扔的时候,都需要解决一个子问题。这个子问题不一定是从k个中选一个,k如果是2的倍数,也可能是从2个中选一个或者从k/2个中选一个。以此类推,这个问题就是将n分解成最小数目个因数的乘积,使得每个因数也都是k的因数。可以把n的因数找出来然后贪心地直接去取。

另一种更容易实现的方法……推出每个因子都也是k的因数以后,可以将这些因子都扩展到k,对最终的结果并没有影响。也就是寻找一个最小的数t,使k^t是n的倍数。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 120050
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;
const ll mod = 1000000007;

int t;
ll n,k;
int num,cnt;
int ans[maxn];

void getnum()
{
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0)ans[num++]=i;
        if(i*i!=n)ans[num++]=n/i;
    }
    ans[num++]=n;
    sort(ans,ans+num);
    ll tmp=n;
    for(int i=num-1;i>=0;i--)
    {
        if(k%ans[i]!=0)continue;
        while(tmp%ans[i]==0)
        {
            tmp/=ans[i];
            cnt++;
        }
    }
    if(tmp!=1)cnt=-1;
}

int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld",&n,&k);
        if(n==1)
        {
            printf("0\n");
            continue;
        }
        if(k==1)
        {
            printf("unbounded\n");
            continue;
        }
        num=0,cnt=0;
        getnum();
        if(cnt==-1)
            printf("unbounded\n");
        else
            printf("%d\n",cnt);
    }
    return 0;
}

B. Failing Components

spfa模板题,求的是从源点出发能到达的点的数目和最远的点的最短距离。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 120050
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;
const ll mod = 1000000007;

int t,n,m,s,num;
int a,b,x,no;
bool flag[maxn],vis[maxn];
int dis[maxn],head[maxn];
struct node
{
    int to;
    int w;
    int nxt;
}e[maxn];

void add(int a,int b,int x)
{
    e[no].to=b;
    e[no].w=x;
    e[no].nxt=head[a];
    head[a]=no++;
}

void spfa(int s)
{
    for(int i=0;i<=n;i++)
        dis[i]=INF,flag[i]=0;
    dis[s]=0,flag[s]=1;
    memset(vis,0,sizeof(vis));
    queue<int>q;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        flag[u]=0;
        for(int i=head[u];i!=-1;i=e[i].nxt)
        {
            int v=e[i].to;
            if(dis[v]>dis[u]+e[i].w)
            {
                dis[v]=dis[u]+e[i].w;
                if(!flag[v])
                {
                    flag[v]=1;
                    q.push(v);
                }
            }
        }
    }
}

int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&s);
        no=0;
        memset(head,-1,sizeof(head));
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&a,&b,&x);
            add(b,a,x);
        }
        spfa(s);
        int ans=0;
        num=0;
        for(int i=1;i<=n;i++)
        {
            if(dis[i]!=INF)
                ans=max(ans,dis[i]),num++;
        }
        printf("%d %d\n",num,ans);
    }
    return 0;
}


D. Lift Problems

一群人要坐电梯上楼,每个人在到达目标楼层之前每停一次就要暴躁一下,如果在目标楼层没停,电梯停下之前每层楼都要暴躁一下。求到顶的时候最小的暴躁值总和。

考虑用dp来做。dp[i]表示从楼底上到第i层停下的最小总和,初始化的时候dp[i]是从楼底上到第i层中途不停的总和。这个初始值包括两个部分,目标楼层第i层以上的人在这里要暴躁一下,第i层一下的人在这之前的一个区间要持续暴躁。

在状态转移的时候,如果在到i之前先在j停了一下,新的暴躁值包括三个部分,1-j层原来的最小暴躁值dp[j],第i层以上的人在i要暴躁一下,以及i-j层的人在这段里持续暴躁。第i层以上的人数可以通过维护前缀和来解决,而i-j区间内的持续暴躁值可以在dp之前做一个预处理,用dis[i][j]表示在i和j停一下而中间不停,区间内人的持续暴躁值的和。预处理和dp的时间复杂度都是O(N^2)。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 1505
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;
const ll mod = 1000000007;

int t,n;
ll a[maxn],sum[maxn];
ll dp[maxn],dis[maxn][maxn];

void init()
{
    memset(dis,0,sizeof(dis));
    for(int i=n;i>=1;i--)
    {
        for(int j=i-1;j>=1;j--)
            dis[i][j]=dis[i][j+1]+(i-j)*a[j];
    }
}
ll Min(ll a,ll b){return a<b?a:b;}

int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        memset(dp,0,sizeof(dp));
        sum[0]=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
        init();
        for(int i=1;i<=n;i++)
        {
            dp[i]=sum[n]-sum[i];
            for(int j=1;j<i;j++)
                dp[i]+=(i-j)*a[j];
        }
        for(int i=2;i<=n;i++)
        {
            for(int j=1;j<i;j++)
                dp[i]=Min(dp[i],dp[j]+dis[i][j+1]+sum[n]-sum[i]);
        }
        printf("%lld\n",dp[n]);
    }
    return 0;
}


F. Runway Planning

签到题,除以10四舍五入取一个u和36-u中的较小值。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 1505
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;
const ll mod = 1000000007;

int t,n;

int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        if(n>180)n-=180;
        int ans=n/10;
        if(n%10>=5)ans++;
        if(ans==0)ans=18;
        printf("%02d\n",ans);
    }
    return 0;
}


H. Talent Selection

n个人有各自的分数,其中你有k个喜欢的,现在要取s个分数最高的,并且你必须为其中k个人加分,求最多可以使多少个你喜欢的被选中。

考虑能选中x个最喜欢的应该怎么操作。将喜欢和普通的初始分数升序排序,加分的时候就是一个贪心的策略。先给喜欢的加,先稳一手把原始分最大的x个人加上最大的x个分数,然后尽力抬一下另外那些原始分不高的,“选不上不亏选上血赚”。然后给普通的人加分,这里要先给原始分较大的s-x个人加,再给剩下的人加。考虑的是如果直接从原始分最小的人开始加,有可能把所有的人都抬到前s名里面。为了预防这样的情况发生,不如索性把较大的分数加给原始分就比较多的人,“选上不亏选不上血赚”。然后把最低的分加给原始分就不高的普通选手,把他们直接做掉。

确定策略以后二分x解决。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 1000050
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;
const ll mod = 1000000007;

int t,n,s,f,k;
int cnt1,cnt2;
int v[maxn];
int w[maxn];
int ans[maxn];
bool cmp(int a,int b)
{
    return a>b;
}

bool solve(int x)
{
    int pos=0;
    for(int i=f-x;i<f;i++)
        ans[i]=w[i]+v[pos++];
    for(int i=f-x-1;i>=0;i--)
        ans[i]=w[i]+v[pos++];
    for(int i=n-(s-x);i<n;i++)
        ans[i]=w[i]+v[pos++];
    for(int i=f;i<n-(s-x);i++)
        ans[i]=w[i]+v[pos++];
    sort(ans,ans+f,cmp);
    sort(ans+f,ans+n,cmp);
    cnt1=0,cnt2=0;
    while(cnt1<f&&cnt1+cnt2<s)
    {
        if(cnt2>=n-f||ans[cnt1]>=ans[f+cnt2])
            cnt1++;
        else cnt2++;
    }
    return cnt1>=x;
}

int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&s,&f);
        for(int i=0;i<n;i++)
            scanf("%d",&w[i]);
        sort(w,w+f);
        sort(w+f,w+n);
        memset(v,0,sizeof(v));
        scanf("%d",&k);
        for(int i=0;i<k;i++)
            scanf("%d",&v[i]);
        sort(v,v+k,cmp);
        int l=0,r=min(s,f)+1;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(solve(mid))l=mid+1;
            else r=mid-1;
        }
        printf("%d\n",r);
    }
    return 0;
}


J. Word Search

直接在矩阵里暴力查找。注意方向有8个,可能有回文,可能长度为1。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 105
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;
const ll mod = 1000000007;

int t,n,m,k,len;
int ansx,ansy,kk;
char s[maxn][maxn];
char r[maxn];
char rr[maxn];
bool flag,vis;
bool w[maxn][maxn];
int pos[4][2]={{0,1},{1,0},{1,1},{1,-1}};

int check1(int x,int y)
{
    if(y+len-1>=m)return 0;
    for(int i=0;i<len;i++)
    {
        if(s[x][y+i]!=r[i])
            return 0;
    }
    ansx=x,ansy=y;
    kk=0;
    return 1;
}
int check2(int x,int y)
{
    if(x+len-1>=n)return 0;
    for(int i=0;i<len;i++)
    {
        if(s[x+i][y]!=r[i])
            return 0;
    }
    ansx=x,ansy=y;
    kk=1;
    return 1;
}
int check3(int x,int y)
{
    if(x+len-1>=n||y+len-1>=m)return 0;
    for(int i=0;i<len;i++)
    {
        if(s[x+i][y+i]!=r[i])
            return 0;
    }
    ansx=x,ansy=y;
    kk=2;
    return 1;
}
int check4(int x,int y)
{
    if(x+len-1>=n||y-len+1<0)return 0;
    for(int i=0;i<len;i++)
    {
        if(s[x+i][y-i]!=r[i])
            return 0;
    }
    ansx=x,ansy=y;
    kk=3;
    return 1;
}

int judge()
{
    int res=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(len==1){
            if(r[0]==s[i][j])
            {
                res++;
                ansx=i,ansy=j;
                kk=0;
                continue;
            }
            else continue;
            }
            res+=check1(i,j);
            res+=check2(i,j);
            res+=check3(i,j);
            res+=check4(i,j);
        }
    }
    return res;
}

int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&k,&n,&m);
        for(int i=0;i<n;i++)
            scanf("%s",s[i]);
        flag=vis=0;
        memset(w,0,sizeof(w));
        for(int i=0;i<k;i++)
        {
            scanf("%s",r);
            if(flag)continue;
            len=strlen(r);
            int tmp=judge();
            memset(rr,0,sizeof(rr));
            for(int j=0;j<len;j++)
                rr[j]=r[len-j-1];
            if(strcmp(rr,r))
            {
                for(int j=0;j<len;j++)
                    r[j]=rr[j];
                //cout<<r<<endl;
                tmp+=judge();
            }
            if(tmp==0)flag=1;
            else if(tmp>1)vis=1;
            else
            {
                int dx=pos[kk][0];
                int dy=pos[kk][1];
                for(int j=0;j<len;j++)
                    w[ansx+dx*j][ansy+dy*j]=1;
            }
        }
        if(flag)printf("no solution\n");
        else if(vis)printf("ambiguous\n");
        else
        {
            bool ccnt=0;
            for(int i=0;i<n;i++)
            {
                for(int j=0;j<m;j++)
                {
                    if(!w[i][j])
                        printf("%c",s[i][j]),ccnt=1;
                }
            }
            if(ccnt)printf("\n");
            else printf("empty solution\n");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/NPU_SXY/article/details/80963644
今日推荐