2017 ACMICPC Asia Regional Shenyang Online

题目链接


01:http://acm.hdu.edu.cn/showproblem.php?pid=6194
02:http://acm.hdu.edu.cn/showproblem.php?pid=6195
03:http://acm.hdu.edu.cn/showproblem.php?pid=6196
04:http://acm.hdu.edu.cn/showproblem.php?pid=6197
05:http://acm.hdu.edu.cn/showproblem.php?pid=6198
06:http://acm.hdu.edu.cn/showproblem.php?pid=6199
07:http://acm.hdu.edu.cn/showproblem.php?pid=6200
08:http://acm.hdu.edu.cn/showproblem.php?pid=6201
09:http://acm.hdu.edu.cn/showproblem.php?pid=6202
10:http://acm.hdu.edu.cn/showproblem.php?pid=6203
11:http://acm.hdu.edu.cn/showproblem.php?pid=6204
12:http://acm.hdu.edu.cn/showproblem.php?pid=6205
这场比赛我们都发挥的还行,a了5道,但是都是前期a的后面再想做题就做不出来了,这就是硬功夫的实力差距啊。

一些题解


02 cable cable cable

 本题的意思是给定K个不同的颜色源,M块显示屏,问任意从M块显示屏中挑选K个,都可以让这k个显示屏显示的颜色都不同,问你需要多少条线将颜色源和显示屏相连。
 这道题其实会发现直接每个颜色源先连接上一块屏幕,如果M-K大于0那么剩下的每块显示屏都必须要分别和每个颜色源相连才能满足条件。得代码。

#include 
using namespace std;
typedef long long  LL;
const int maxn=1e5+10;
const int INF=0x3f3f3f3f;
int main()
{
    LL m,k;
    while(~scanf("%lld %lld",&m,&k))
    {
       LL ans=(m-k)*k+k;
        printf("%lld\n",ans);
    }
    return 0;
}

04 array array array

 题意很简单,就是看给定n个数字看看去掉k个数字能不能让这串数字变成严格递增或递减数列。ps:non-increasing order or non-decreasing order这句话真是坑死了。
 那么其实就是LIS求两遍最长上升子序列。

#include 
using namespace std;
typedef long long  LL;
const int maxn=1e5+10;
const int INF=0x3f3f3f3f;
const int MAXN=100010;
int a[MAXN],dp[MAXN];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,k;
        int ans1,ans2;
        scanf("%d %d",&n,&k);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        memset(dp,INF,sizeof(dp));
        for(int i=1;i<=n;i++)
            *lower_bound(dp+1,dp+n+1,a[i])=a[i];
        ans1=lower_bound(dp+1,dp+n+1,INF)-(dp+1);
         for(int i=1;i<=n;i++)
            a[i]=-a[i];
        memset(dp,INF,sizeof(dp));
        for(int i=1;i<=n;i++)
            *lower_bound(dp+1,dp+n+1,a[i])=a[i];
        ans2=lower_bound(dp+1,dp+n+1,INF)-(dp+1);
        //cout<
        if(ans1+k>=n||ans2+k>=n) printf("A is a magic array.\n");
        else printf("A is not a magic array.\n");

    }

    return 0;
}

05 number number number

 题意有点绕,说的是给定F0 = 0,F1 = 1,告诉你Fn = F(n - 1) + F(n - 2)再给你一个K让你找一个最小的数n使任意满足条件Fa1 + …Fak都不等于n。
 那么其实每次不能等于的都是3 + 2 * k次个的数的值 - 1,找规律矩阵快速幂即可

#include 
using namespace std;
const int mod = 998244353;
const int N = 2;
struct Matrix
{
    __int64 v[N][N];
    Matrix()
    {
        memset(v,0,sizeof(v));
    }
};
Matrix multi(Matrix p1,Matrix p2)
{
    Matrix res;
    for(int i=0;ifor(int j=0;jif(p1.v[i][j])
                for(int k=0;kreturn res;
}
Matrix pow(Matrix p,__int64 k)
{
    Matrix t;
    for(int i=0;i1;
    while(k)
    {
        if(k&1)
            t=multi(t,p);
        p=multi(p,p);
        k=k>>1;
    }
    return t;
}
int main()
{
    __int64 k;
    while(scanf("%I64d",&k)!=EOF)
    {
        __int64 n = 3+2*k;
        Matrix e,ans;
        e.v[0][0]=e.v[0][1]=e.v[1][0]=1;
        e.v[1][1]=0;
        ans = pow(e,n);
        printf("%I64d\n",(ans.v[0][1]+mod-1)%mod);
    }

    return 0;
}

08 transaction transaction transaction

 这道题是说有一个商人去买卖书籍,他只能从一个地方进货,一个地方出货,告诉你地点的连通情况和路费以及各个地点的书的价格,问商人最多能赚多少
 那这就是一道普通的spfa最长路,建立超级源点和超级汇点都和每一个点相连,书的价格与超级源点连时为正,路费为正,书价和超级汇点相连为负,求最短路即可。

#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 100004;
const int INF = 0x3f3f3f3f;
int head[maxn];
int d[maxn];
int visit[maxn];
int n;
struct Edge
{
    int to,w,next;
}E[maxn<<4];
int sizee;
void init()
{
    memset(head,-1,sizeof(head));
    memset(d, INF, sizeof(d));
    memset(visit, 0, sizeof(visit));
    sizee = 0;
}

void addedge(int u,int v,int x)
{
    E[sizee].to = v;
    E[sizee].w = x;
    E[sizee].next = head[u];
    head[u] = sizee++;
}

void SPFA(int s)
{
    queue<int> q;
    visit[s] = 1;
    d[s]=0;
    q.push(s);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        visit[u] = 0;
        for(int i=head[u]; i!=-1; i=E[i].next)
        {
            if(d[E[i].to] > d[u] + E[i].w)
            {
                d[E[i].to] = d[u]+E[i].w;
                if(!visit[E[i].to]){
                    visit[E[i].to] = 1;
                    q.push(E[i].to);
                }
            }
        }
    }
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d", &n);
        init();
        for(int i = 1;i <= n;i++)
        {
            int ls;
            scanf("%d", &ls);
            addedge(0, i, ls);
            addedge(i, n + 1, -ls);
        }
        for(int i = 1;i <= n - 1;i++)
        {
            int a, b, c;
            scanf("%d%d%d",&a, &b, &c);
            addedge(a, b, c);
            addedge(b, a, c);
        }
        SPFA(0);
        if(d[n + 1] >= 0)
            printf("0\n");
        else
            printf("%d\n", -d[n + 1]);
    }
    return 0;
}

12 card card card

 这题就是每次给定几组数据,每组数据有两个值,一个是获得值,一个是消费值。可以预处理数据将前面的几组数据放到最后去,问到当前总积累值小于当前消费值时经手(拿到手的)数据的组数。
 其实这道题就是相当于连续累计最大数。将获得值和消费值做差作为权值,然后由于是个环我们规定跑到2 * n - 1便,然后又由于只有n组数据,那么如果当前累计的个数已经到达n了就跳出。那么在跑的时候,遇到累计变成负的了就初始化状态,否则更新状态即可。

#include 
#include 
#include 
#include 
using namespace std;
int stand[2000010];
int value[2000010];
int n;
int main()
{
    while(~scanf("%d", &n))
    {
        for(int i = 1;i <= n;i++)
            scanf("%d", &stand[i]), value[i] = stand[i];
        for(int i = 1;i <= n;i++)
        {
            int ls;
            scanf("%d", &ls);
            stand[i] -= ls;
        }
        int ans = 0;
        int dq = 0;
        int dqval = 0;
        int cnt = 0;
        int bj = 0;
        int ks = 1;
        for(int i = 1;i <= 2 * n - 1;i++)
        {
            int ls = i % n;
            if(ls == 0)
                ls = n;
            if(dq + stand[ls] < 0)
            {
                dq = 0;
                cnt = 0;
                dqval += value[ls];
                if(dqval > ans)
                {
                    bj = ks;
                    ans = dqval;
                }
                dqval = 0;
                ks = i + 1;
            }
            else
            {
                dq += stand[ls];
                cnt++;
                dqval += value[ls];
                if(dqval > ans)
                {
                    bj = ks;
                    ans = dqval;
                }
                if(cnt == n)
                {
                    cnt = 0;
                    dq = 0;
                    dqval = 0;
                    ks = i + 1;
                }
            }
        }
        printf("%d\n", bj - 1);
    }
    return 0;
}

你可能感兴趣的:(比赛)