ICPC——2021台湾站(A B C D E J)

A - Olympic Ranking

题意:n支队伍,各有一定数量的金牌,银牌,铜牌。按照金牌 > 银牌 > 铜牌的优先级,找出最强的队伍。

题解:题意简单,难点在于输入那个字符串。
<1> 使用 getline和 string配合,然后输出的时候从第 1位输出而不是第 0位,会 wa12。
<2> 我是手写了一个输入字符串的函数。
<3> 我队友用的 map + tuple + string,也把代码附上,可以做个参考。(%%%

代码<2>

#include<bits/stdc++.h>
using namespace std;

#define endl "\n"
#define ll long long
#define inf 0x3f3f3f3f
#define infll 1e15+7
#define IOS ios::sync_with_stdio(0); cin.tie(0)
#define debug(a) cout<<"*****\tdebug: "<<a<<"\t*****"<<endl;
const double eps = 1e-7;
const double pi = acos(-1.0);
const int mod = 1e9+7;
const int N = 5 + 1e3;

void getstr(char s[], int Lim)
{
	int i = 0;
	char ch = getchar();
	while(ch == ' ') ch = getchar();
	while(ch != '\n' && ch != EOF && i < Lim)
	{
		s[i++] = ch;
		ch = getchar();
	}
	s[i] = 0;
}

int a[N], b[N], c[N];
char s[310][100000];

int main()
{
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif
	// IOS;
// ---------------------------------------------------------------
	int n; cin>>n;
	for(int i = 1; i <= n; i++)
	{
		cin>>a[i]>>b[i]>>c[i];
		getstr(s[i], 100000);
	}	
	int ans = 1;
	for(int i = 2; i <= n; i++)
		if((a[i] > a[ans]) || (a[i] == a[ans] && b[i] > b[ans]) || (a[i] == a[ans] && b[i] == b[ans] && c[i] > c[ans])) 
			ans = i;
	printf("%s", s[ans]);
	return 0;
}

代码:<3>
在这里插入图片描述

B - Aliquot Sum

题意:求一个数的因子之和(除了自己本身),然后和自身比大小,对应输出三种字符串。

题解:预处理一下即可。

代码

#include<bits/stdc++.h>
using namespace std;

#define endl "\n"
#define ll long long
#define inf 0x3f3f3f3f
#define infll 1e15+7
#define IOS ios::sync_with_stdio(0); cin.tie(0)
#define debug(a) cout<<"*****\tdebug: "<<a<<"\t*****"<<endl;
const double eps = 1e-7;
const double pi = acos(-1.0);
const int mod = 1e9+7;
const int N = 5 + 1e6;

ll ans[N];

int main()
{
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif
	// IOS;
// ---------------------------------------------------------------
	for(int i = 1; i < 1000010; i++)
		for(int j = 2*i; j < 1000010; j += i)
			ans[j] += i;
	// for(int i = 1; i <= 20; i++) cout<<ans[i]<<endl;
	int T; cin>>T;
	while(T--)
	{
		int x; cin>>x;
		if(ans[x] > x) cout<<"abundant"<<endl;
		else if(ans[x] == x) cout<<"perfect"<<endl;
		else cout<<"deficient"<<endl;
	}
	return 0;
}

C - A Sorting Problem

题意:给定一个数组,求逆序对数。

题解:板子题,树状数组跑一遍即可。

代码

#include<bits/stdc++.h>
using namespace std;

#define endl "\n"
#define ll long long
#define inf 0x3f3f3f3f
#define infll 1e15+7
#define IOS ios::sync_with_stdio(0); cin.tie(0)
#define debug(a) cout<<"*****\tdebug: "<<a<<"\t*****"<<endl;
const double eps = 1e-7;
const double pi = acos(-1.0);
const int mod = 1e9+7;
const int N = 5 + 1e6;


int n;
int tree[N], f[N];
struct node
{
    int x, idx;
}a[N];

bool cmp(node a, node b)
{
    return a.x < b.x;
}

int lowbit(int i)
{
    return i & -i;
}

void update(int pos, int val)
{
    for(int i = pos; i <= n; i += lowbit(i))
        tree[i] += val;
}

int ask(int pos)
{
    int res = 0;
    for(int i = pos; i > 0; i -= lowbit(i))
        res += tree[i];
    return res;
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif
	IOS;
// ---------------------------------------------------------------
	cin>>n;
	for(int i = 1; i <= n; i++)
	{
		cin>>a[i].x;
		a[i].idx = i;
	}
	sort(a+1, a+n+1, cmp);

	f[a[1].idx] = 1;
	for(int i = 2; i <= n; i++)
	{
		if(a[i].x != a[i-1].x) f[a[i].idx] = i;
		else f[a[i].idx] = f[a[i-1].idx];
	}
	ll ans = 0;
	for(int i = 1; i <= n; i++)
	{
		update(f[i], 1);
		ans += i - ask(f[i]);
	}
	cout<<ans<<endl;
	return 0;
}

D - Drunk Passenger

题意:n个人按照先后顺序上飞机坐座位,第一个人喝醉了,所以他会等可能地坐到除了自己位置之外的位置上。剩下的乘客,如果自己的位置被占了,就会等可能的坐到其他位置上,否则坐自己的位置。求最后一个人做对位置的概率。

题解:【醉汉、1、2、3 …n-2、最后一个人】 分两种大情况:

<1> 醉汉先坐你的位置( 1 / ( n − 1 ) 1/(n-1) 1/(n1)
那么最后一个人坐错位置的概率为 1 ∗ ( 1 / ( n − 1 ) ) 1*(1/(n-1)) 1(1/(n1)) = 1 / ( n − 1 ) 1/(n-1) 1/(n1),则坐对位置的概率也为 1 / ( n − 1 ) 1/(n-1) 1/(n1)

<2> 醉汉坐其他人的位置 ( ( n − 2 ) / ( n − 1 ) (n-2)/(n-1) (n2)/(n1) )
假如醉汉坐到了第 x个人的位置,那么从第 2个到第 x-1个人都会坐到自己的位置上。然后剩下的位置第 x个人都可以坐。
或者说情况就变成了:一共 m个人,m个位置(m = n-x+1),每个人都等概率坐任意位置(但还保持那种坐自己位置的特性)。那么最后一个人坐到最后一个位置上的概率就是 1/2(这是个经典的醉汉问题,或者说疯子问题,这里挂一个知乎的链接,就是关于这个问题的若干个解释,不再给出证明知乎醉汉上飞机问题链接

这种情况下,最后一个人坐对位置的概率就是 ( 1 / 2 ) ∗ ( ( n − 2 ) / ( n − 1 ) ) (1/2) * ((n-2)/(n-1)) (1/2)((n2)/(n1))

那么两种情况相加一下,就是 1 / ( n − 1 ) 1/(n-1) 1/(n1) + ( 1 / 2 ) ∗ ( ( n − 2 ) / ( n − 1 ) ) (1/2) * ((n-2)/(n-1)) (1/2)((n2)/(n1)) = n / ( 2 ∗ ( n − 1 ) ) n/(2*(n-1)) n/(2(n1))

代码

#include<bits/stdc++.h>
using namespace std;

#define endl "\n"
#define ll long long
#define inf 0x3f3f3f3f
#define infll 1e15+7
#define IOS ios::sync_with_stdio(0); cin.tie(0)
#define debug(a) cout<<"*****\tdebug: "<<a<<"\t*****"<<endl;
const double eps = 1e-7;
const double pi = acos(-1.0);
const int mod = 1e9+7;
const int N = 5 + 1e6;

int main()
{
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif
	IOS;
// ---------------------------------------------------------------
	int n; cin>>n;
	double ans = 1.0*n/(2*(n-1));
	cout<<ans;
	return 0;
}

E - Eatcoin

题意:简单地说,在第 d天,花费 p块钱,生产 q ∗ d 5 q*d^5 qd5块钱。 生产到 1 0 99 10^{99} 1099 块钱算富豪。每天必须先花费 p块钱才能生产。求开始时最少需要有多少钱,以及在开始时有需要的最少钱的情况下,最少需要多少天才能变成富豪。

题解:首先要推出 1 5 + 2 5 + 3 5 + . . . + n 5 1^5 + 2^5 + 3^5 + ...+n^5 15+25+35+...+n5的公式为: ( n 2 ∗ ( n + 1 ) 2 ∗ ( 2 n 2 + 2 n − 1 ) ) / 12 (n^2*(n+1)^2*(2n^2 + 2n-1)) / 12 (n2(n+1)2(2n2+2n1))/12
用那个组合数的公式应该也可以(公式证明链接

<1> 求开始最少需要多少钱
刚开始花的钱的多,之后生产的钱多。假如到第 x天,生产的钱的总和大于等于花费的钱的总和。所以答案为,前x-1天花费总数 - 前x-1天生产总数 + 第 x天的花费

<2> 求最少需要多少天
列出求手上钱的总数的式子,然后二分天数即可。

代码:(python版本, c++版本的大数写的一直有问题,还在debug)

def cal(n, p, q, x):
    return q*(n*n)*(n+1)*(n+1)*(2*n*n+2*n-1)//12 - p*n + x

p, q = map(int, input().split())
last = p - q
i = 2
while(1):
    now = i*p-q*(i*i)*(i+1)*(i+1)*(2*i*i+2*i-1)//12
    i += 1
    if now >= last:
        last = now
    else:
        print(last+p)    #下一次需要先消耗
        break

l = 1
r = 10**100
ans = 0
x = last+p  # 不要x也能过,答案太大,x没影响?
while l <= r:
    mid = (l+r)//2
    if cal(mid, p, q, x) < 10**99:
        l = mid+1
    else:
        r = mid-1
        ans = mid
print(ans)

J - JavaScript

题意:模拟 javascript的减法运算。给定两个字符串a b,如果字符串中存在非数字的元素,输出 NaN。否则将两个字符串转为数字,进行相减运算。

题解:简单模拟即可。(0对应的 ASCLL值为 48)

代码

#include<bits/stdc++.h>
using namespace std;

#define endl "\n"
#define ll long long
#define inf 0x3f3f3f3f
#define infll 1e15+7
#define IOS ios::sync_with_stdio(0); cin.tie(0)
#define debug(a) cout<<"*****\tdebug: "<<a<<"\t*****"<<endl;
const double eps = 1e-7;
const double pi = acos(-1.0);
const int mod = 1e9+7;
const int N = 5 + 1e3;

int main()
{
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif
	// IOS;
// ---------------------------------------------------------------
	string a, b; cin>>a>>b;
	bool falg = 0;
	for(int i = 0; i < a.size(); i++) 
		if(!isdigit(a[i]))
			falg = 1;
	for(int i = 0; i < b.size(); i++) 
		if(!isdigit(b[i]))
			falg = 1;
	if(falg) cout<<"NaN";
	else
	{
		int ans1 = 0, ans2 = 0;
		for(int i = 0; i < a.size(); i++) ans1 = ans1*10 + a[i] - 48;
		for(int i = 0; i < b.size(); i++) ans2 = ans2*10 + b[i] - 48;
		cout<<ans1-ans2; 
	}
	return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值