The 2018 ACM-ICPC Chinese Collegiate Programming Contest (NingXia) 一些题解

A. Maximum Element In A Stack
求出一个出栈入栈序列中,每一次操作进行完成后,栈内最大的元素。
首先我们维护两个栈,一个栈保存最大值,一个栈正常操作。我们只维护一个最大值的栈的情况就可以了。
进栈:如果当前进栈的值大于等于最大值栈顶的值,其他值就不管了
出栈:如果当前出栈的元素等于最大值栈的元素,那么最大值栈也要出栈。否则的话就不管了
这样下来,最大值栈的栈顶元素就是我们想要的最大值。
正确性的相关证明就留给读者了

#include <bits/stdc++.h>
#include<cstring>
#define ll long long
using namespace std;
const int MAXN = 5e6 + 5;
ll st[MAXN],sst[MAXN];
int n, p, q, m;
unsigned int SA, SB, SC;
unsigned int rng61()
{
    SA ^= SA << 16;
    SA ^= SA >> 5;
    SA ^= SA << 1;
    unsigned int t = SA;
    SA = SB;
    SB = SC;
    SC ^= t ^ SA;
    return SC;
}
void gen(int cat)
{
    scanf("%d%d%d%d%u%u%u", &n, &p, &q, &m, &SA, &SB, &SC);
    ll ans = 0LL;
    int tp1 = 0,tp2 = 0;
    for(int i = 1; i <= n; i++)
    {
        if(rng61() % (p + q) < p)
        {
            //PUSH(rng61() % m + 1);
            ll now = 1LL*(rng61() % m + 1);
            //cout<<"push:"<<now<<endl;
            st[++tp1] = now;
            if(sst[tp2] <= now)
            {
                sst[++tp2] =  now;
            }
        }
        else
        {
            //POP();
            // cout<<"pop"<<endl;
            if(tp2 > 0&& st[tp1] == sst[tp2])
            {
                tp2--;
            }
            if(tp1 > 0)
                tp1--;
        }
        //cout<<i<<": "<<sst[tp2]<<endl;
        if(tp1 && tp2) ans ^= (1LL*i*sst[tp2]);
    }
    printf("Case #%d: %lld\n",cat,ans);
}
void check()
{
    ll ans = 0;
    int tp1 = 0,tp2 = 0;
    cin>>n;
    for(int i = 1; i <= n; i++)
    {
        int op ;
        cin>>op;
        if(op != -1)
        {
            //PUSH(rng61() % m + 1);
            int now = op;
            //cout<<"push:"<<now<<endl;
            st[++tp1] = now;
            if(sst[tp2] <= now)
            {
                sst[++tp2] = now;
            }
        }
        else
        {
            //POP();
            // cout<<"pop"<<endl;
            if(tp2 > 0 && st[tp1] >= sst[tp2])
            {
                tp2--;
            }
            if(tp1 > 0)
                tp1--;
        }
        cout<<i<<": "<<sst[tp2]<<endl;
        //ans ^= (1LL*i*sst[tp2]);
    }
}
int main()
{
    int ca,cat = 1;
    scanf("%d",&ca);
    while(ca--)
    {
        memset(st,0,sizeof(st));
        memset(sst,0,sizeof(sst));
        gen(cat++);
        //check();
    }
    return 0;
}

B. Rolling The Polygon
强行用余弦定理算出每次翻转的角度,然后计算一下圆弧长就行

#include <bits/stdc++.h>
#include<cstring>
using namespace std;
const double pi=acos(-1.0);
struct node{
double x,y;
}z[150];
int n;
double x11,y11;
double solve(int t){
    double a=(z[t].x-z[(t-1+n)%n].x)*(z[t].x-z[(t-1+n)%n].x)+(z[t].y-z[(t-1+n)%n].y)*(z[t].y-z[(t-1+n)%n].y);
    double b=(z[t].x-z[(t+1+n)%n].x)*(z[t].x-z[(t+1+n)%n].x)+(z[t].y-z[(t+1+n)%n].y)*(z[t].y-z[(t+1+n)%n].y);
    double c=(z[(t-1+n)%n].x-z[(t+1+n)%n].x)*(z[(t-1+n)%n].x-z[(t+1+n)%n].x)+(z[(t-1+n)%n].y-z[(t+1+n)%n].y)*(z[(t-1+n)%n].y-z[(t+1+n)%n].y);
    double ans=(a+b-c)/(2*sqrt(a)*sqrt(b));
    ans=acos(ans);
    double num=sqrt((x11-z[t].x)*(x11-z[t].x)+(y11-z[t].y)*(y11-z[t].y));
    return num*(pi-ans);
}
int main()
{
    int t;
    cin>>t;
    cout<<fixed<<setprecision(3);
    for(int ca=1;ca<=t;ca++){
        cin>>n;
        for(int i=0;i<n;i++){
            cin>>z[i].x>>z[i].y;
        }
        cin>>x11>>y11;
        double sum=0;
        for(int i=0;i<n;i++){
            sum+=solve(i);
        }
        cout<<"Case #"<<ca<<": "<<sum<<endl;
    }
    return 0;
}

C. Caesar Cipher
很水的模拟
D. Take Your Seat
题意是编号为1的人随机坐在一个座位上,如果照编号顺序上飞机的人发现自己的座位被占了,该乘客就会随机选一个座位,问最后一个上飞机的人坐在自己座位正确位置上的概率是多少?
这是第一问,第二问上飞机的顺序也是随机的,同样求最后一个上飞机的人坐在自己位置上的概率。
我们先考虑的一个问题,如果只有一个人的话,概率是1,如果有两个人的话,说明第一个人做回了自己的座位,这个概率就是0.5,我们强行找一波规律,发现都是1/2……
问题2只要先列出来各种情况,同样找规律就ok
H. Fight Against Monsters
简单贪心,预处理杀死每个怪物的次数,选择(ATK/次数)最高的怪物优先杀死,可以证明一定是及最优的
F. Moving On 题
题意就是最短路,要求每次询问最短路的时候经过的点上的权值不超过一个值。
首先只有50个点,肯定是floyd算法,想到Floyd的dp思想,我们尝试加一维上去,设dp[i][j][k] 为从i到j,压力值都再前k小的路径上的最小值。
我们把枚举第k小的时候,相当于还是判断了走第k小的那个中继点的最优性。
也就是dp[i][j][k] = min(dp[i][j][k-1] ,dp[i][kk][k-1] + dp[kk][j][k-1])
意思是走或者不走,都会将前k-1小的值向上更新,这里需要保存原来这些点的位置。

#include <bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
const int MAXN = 201;
const int INF = 0x3f3f3f3f;
int w[MAXN],ww[MAXN];
int dp[MAXN][MAXN][MAXN];
int id[MAXN];
int main()
{
    int ca,cat = 1;
    scanf("%d",&ca);
    while(ca--)
    {
        int n,q;
        scanf("%d%d",&n,&q);
        int u,v,d;
        for(int i = 1;i<=n;i++) {
                scanf("%d",&w[i]);
                id[i] = i;
        }
        sort(id+1,id+n+1,[&](int x,int y)
             {
                 return w[x] < w[y];
             });
        sort(w+1,w+n+1);
        memset(dp,INF,sizeof(dp));
        for(int i = 1;i<=n;i++)
        {
            for(int j = 1;j<=n;j++)
            {
                scanf("%d",&dp[i][j][0]);
            }
        }
        for(int k = 1;k<=n;k++)
        {
            int kk = id[k];
            for(int i = 1;i<=n;i++)
            {
                for(int j = 1;j<=n;j++)
                {
                    dp[i][j][k] = min(dp[i][j][k-1],dp[i][kk][k-1]+dp[kk][j][k-1]);
                }
            }
        }
        printf("Case #%d:\n",cat++);
        while(q--)
        {
            int u,v,d;
            scanf("%d%d%d",&u,&v,&d);
            int t;
            for(t = 1;t<=n;t++)
            {
                if(w[t] > d)
                {
                    break;
                }
            }
            printf("%d\n",dp[u][v][t-1]);
        }
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值