The 2018 ACM-ICPC Chinese Collegiate Programming Contest/The 2019 Asia Yinchuan First Round On(部分题解)

A、 Maximum Element In A Stack

计蒜客
要点:在栈中进栈、入栈操作,并维护栈中最大值,每次操作过后用最大值*此次操作数n与前一次计算后的值异或,栈为空则输出0,0与任何数异或都为0,所以没啥影响。

#include <set>
#include <map>
#include <queue>
#include <cmath>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#pragma pack(4)

#define ll long long
#define ull unsigned long long
#define pii pair<int, int>
#define pll pair<ll, ll>
#define mid (r+l)*0.5
#define l (d<<1)
#define r ((d<<1)&1)
#define in(c) (c-'0')
#define ch(i) (i+'0')

const int N=5000007;
const int M=2500;
const int inf=0x3f3f3f;
const double eps=1e-6;
const ll mod=530600414;

int n, p, q, m;
ll ans;
int cnt;
ll maxn[N];
vector<ll> ve;

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(){
    scanf("%d%d%d%d%u%u%u", &n, &p, &q, &m, &SA, &SB, &SC);
    for(int i = 1; i <= n; i++)
    {
        if(rng61() % (p + q) < p)
        {
            ve.push_back(rng61() % m + 1);
            maxn[cnt]=max(maxn[cnt-1],ve.back());//维护栈内最大值
            ans=ans^(i*maxn[cnt]);
            cnt++;
        }
        else
        {
            if(!ve.empty())
            {
                ve.pop_back();
                //cout<<ve.top()<<endl;
                cnt--;
                maxn[cnt]=0;//清零操作,可省略
                ans=ans^(i*maxn[cnt-1]);
            }
        }
    }
}

int main()
{
    int t;
    int cas=0;
    scanf("%d",&t);
    while(t--)
    {
        while(!ve.empty())
        {
            ve.pop_back();
        }//ve.clear()清空上次样例的操作
        ans=0;
        cnt=1;
        memset(maxn, 0, sizeof(maxn));
        gen();
        printf("Case #%d: %lld\n",++cas,ans);
    }
    return 0;
}

B、Rolling The Polygon

计蒜客
每一次旋转时相当于以转点(多边形旋转时不动的那个点)为圆心,此点到转点的距离为半径,旋转角度为转点的外角。即给定点到多边形每个点的距离为旋转半径,每个顶点对应外角为旋转角度。
要点:求外角,注意精度要足够大,不然最后结果误差较大。

#include <set>
#include <map>
#include <queue>
#include <cmath>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#pragma pack(4)

#define ll long long
#define ull unsigned long long
#define pii pair<int, int>
#define pll pair<ll, ll>
#define mid (r+l)*0.5
#define l (d<<1)
#define r ((d<<1)&1)
#define in(c) (c-'0')
#define ch(i) (i+'0')

const int N=57;
const int M=2500;
const int inf=0x3f3f3f;
const double eps=1e-6;
const ll mod=530600414;

pii a[N],ta;

double dis(pii a,pii b)
{
    return sqrt((a.first-b.first)*(a.first-b.first)+(a.second-b.second)*(a.second-b.second));
}//两点间距离

double sita(pii a,pii b,pii c)
{
    return 3.1415926535-acos(((a.first-b.first)*(c.first-b.first)+(a.second-b.second)*(c.second-b.second))/(dis(a, b)*dis(b,c)));
}//求b外角

int main()
{
    int t;
    int cas=0;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        double ans=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&a[i].first,&a[i].second);
        }
        scanf("%d%d",&ta.first,&ta.second);//点坐标
        for(int i=0;i<n;i++)
        {
            ans+=dis(ta,a[i])*sita(a[(i-1+n)%n],a[i],a[(i+1)%n]);
        }//弧长:半径×角
        printf("Case #%d: %.3lf\n",++cas,ans);
    }
    return 0;
}


C、Caesar Cipher

计蒜客
就是一个移位密码的题,选择用数组存字母减去’A’的ASCII码,最后加上’A’,就不用考虑26个字母间的循环问题了。这题只有大写字母,少了很多坑。
1、C++

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int s1[51],s2[51],s3[51];

int main(){
	int T;
	cin>>T;
	for(int t=1;t<=T;t++){
		int n,m;
		cin>>n>>m;
		char ch;
		for(int i=0;i<n;i++){
			cin>>ch;
			s1[i]=ch-'A';
		}
			
		for(int i=0;i<n;i++){
			cin>>ch;
			s2[i]=ch-'A';
		}
		
		int len=(s2[0]-s1[0])%26;
		for(int i=0;i<m;i++){
			cin>>ch;
			s3[i]=ch-'A';
		}
		cout<<"Case #"<<t<<": ";
		for(int i=0;i<m;i++){
			char x=(s3[i]-len+26)%26;
			cout<<char(x+'A');
		} 			
		cout<<endl;
	}
	return 0;
} 

2、python

t=int(input())
for i in range(t):
    n,m=map(int,input().split())
    str1=input()
    str2=input()
    s=input()
    dis=ord(str2[0])-ord(str1[0])
    print("Case #"+str(i+1)+": ",end="")
    for a in s:
        print(chr(ord('A')+(ord(a)-ord('A')-dis+26)%26),end="")
    print("")

D、Take Your Seat

计蒜客
题解:注意按顺序上车的话拿错号的主人公一直是第一个上,需要讨论他上去做的位子,后一个上车的人如果发现自己位子没有被占的话一定会按着自己的座位号坐,依此类推,后面的人都会坐在正确的位置上。
举几个例子可以很快发现:按顺序上飞机,概率一直是1/2(要特判a==0的情况);
随机时,考虑主人公第几个上。最后一个上的时候,前面都坐好了,此时一定坐对,概率1/b;其他顺序概率都是1/b1/2,举个例子,第二个上,第一个人有号码牌,已经坐好了,现在相当于求b-1个人按顺序上最后一个人坐对的概率,前面求过了是概率为1/2。
最后得到式子:**(b+1)/(2
b)**。
python写:
map:第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。

n=int(input())
for i in range(n):#从0开始
    a,b=map(int,input().split());#用于一行输入用户的多个值
    print("Case #"+str(i+1)+": ",end="")
    if a > 1:
    	print("0.500000",end=" ")
    else:
        print("1.000000",end=" ")
    c=(b+1)/(2*b)
    print('%.6f' % c)

H、Fight Against Monsters

计蒜客
lower_bound( )和upper_bound( )都是利用二分查找的方法在一个升序排列的数组中进行查找的。

lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于 num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
upper_bound( begin,end,num):不同之处是:查找第一个大于num的数字。

降序排列数组中,要重载lower_bound()和upper_bound():lower_bound( begin,end,num,greater() )

题解:伤害值是累加增长的,斐波拉契数列形式,在atk<=10^5题意下,最多到500(打表知)。所以可以找到每个怪物需要多少次打击(id值)才能死亡,sum存所有活着的怪物的攻击值,每次打死一只要更新sum值。
先打a后打b的排序规则是:a,b攻击值的和 * 打击a所需次数+b攻击值 * 打击b所需次数<a,b攻击值的和 * 打击b所需次数+a攻击值 * 打击a所需次数

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn=1e5+10;
int a[510];
struct node{
	int hp,atk,id;
}mst[maxn];
bool cmp(node a,node b){
	return (a.atk+b.atk)*a.id+b.id*b.atk<(a.atk+b.atk)*b.id+a.id*a.atk;
}
int main(){
	int T;
	cin>>T;
	for(int i=1;i<=500;i++)
		a[i]=a[i-1]+i;
		
	for(int t=1;t<=T;t++){
		int n;
		long long sum=0;
		cin>>n;
		for(int i=0;i<n;i++){
			cin>>mst[i].hp>>mst[i].atk;
			mst[i].id=lower_bound(a+1,a+501,mst[i].hp)-a;//找到能打死此怪物的最小的打击次数
			sum+=mst[i].atk;
		}
			
		sort(mst,mst+n,cmp);
		long long ans=0;
		for(int i=0;i<n;i++){
			ans+=sum*mst[i].id;//活着的怪物都会在打死某一只怪物的过程中攻击,所以sum*id
			sum-=mst[i].atk;//更新打击总值		
		}
		cout<<"Case #"<<t<<": "<<ans<<endl;
	}
	return 0;
} 
发布了54 篇原创文章 · 获赞 26 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_43629813/article/details/100176551