Codeforces Round #503 (by SIS, Div. 2)

传送

打cf就是在做英语阅读。。。

线上AB题,+补C题, D,E补不动。(@_@;)

A

题意:

给你n个h高的楼,他们在一块排列,再给你一个a,b值  意思是在 a层到b层之间都是有通向其他楼的通道,经过一个楼用1min

所有楼都一样,只有a层到b层之间有,然后有k个询问,问你从ta楼fa层到tb楼fb层需要花多少时间,在一个楼内上下楼也只要1min

思路:

分情况

1:在同一个楼内  需要abs(fa - fb)

2:在不同楼内, 如果有一方所在的楼层有通向别的楼的通道,那么则是

abs(ta - tb) + abs(fa - fb);

否则:随便找一方看它离a近还是b近  需要先走到 有通向别的楼的通道的层,在继续走

#include 
using namespace std;
typedef long long ll;
ll n, h, a, b, k;

int main()
{
	ios::sync_with_stdio(false);

	cin >> n >> h >> a >> b >> k;

	ll ta, fa, tb, fb;

	for(ll i = 1;i <= k;i ++)
    {
        ll ans = 0;
        cin >> ta >> fa >> tb >> fb;

        if(ta == tb)
            ans = abs(fa - fb);
        else
        {
            if((fa >= a && fa <= b) || (fb >= a && fb <= b))
            {
                ans =  abs(ta - tb) + abs(fa - fb);
            }
            else
            {
                ll s1 = abs(ta - tb);
                ll s2, p;
                if(abs(fa - a) > abs(fa - b))
                {
                    s2 = abs(fa - b);
                    p = b;
                }
                else
                {
                    s2 = abs(fa - a);
                    p = a;
                }
                ll s3 = abs(p - fb);
                ans = s1 + s2 + s3;
            }
        }
        cout << ans << '\n';
    }
}

 

B

题意:

有n个学生,还以一个长度为n的序列,就是每个学生对应说的话(他们所指向的人的序号),需要你找出第一个胸前有两个印章的人,(看例子解释很容易看懂)

思路:

分情况:

1:如果需要为i的人先说了自己,即下标为i的人 a[i] = i  那么一定是这个i  

2:否则按照所说的话找,不断记录前一个人所说的序号,直到第一个印章数为2的人出现,然后记录即可,模拟完所有人

一起输出答案

#include 
using namespace std;
typedef long long ll;

int a[1005];
int vis[1005];
vector ans;

int main()
{
	ios::sync_with_stdio(false);
	int n;
	cin >> n;
	for(int i = 1;i <= n;i ++)
        cin >> a[i];

    for(int i = 1;i <= n;i ++)
    {
        memset(vis,0,sizeof(vis));

        vis[i] ++;

        int t = a[i];
        while(1)
        {
            vis[t] ++;
            if(vis[t] == 2)
            {
                ans.push_back(t);
                break;
            }
            t = a[t];
        }
    }
    for(int i = 0;i < ans.size();i ++)
    {
        if(i)
            cout << " ";
        cout << ans[i];
    }
    return 0;
}

C:

题意:

告诉你有n个学生,m个党派,其中输入数据会告诉你每个人它选了哪个党派,并且他改变主意需要花多少钱。

你的任务是确保1号党派赢的前提下使用的钱最少,

思路:

首先可以想到贪心,但是肯定不能完全正确,因为数据可能很奇葩。。。

所有我们可以枚举所有情况,保证买少的票,花最少的钱可以赢

从 0 枚举到n 取最小值

#include 
using namespace std;
typedef long long ll;
pair v[3005];
ll w[3005],c[3005],ans = 1e18;
bool cmp1(pair a,pair b)
{
	return a.second < b.second;
}
int main()
{
	ll n,m;
	
	cin>>n>>m;
	
	for(ll i = 1;i <= n; ++i)
	{
		cin>>v[i].first>>v[i].second;
	}
	//按照ci 升序
	sort(v + 1,v + n + 1,cmp1);
	
	//枚举最多的得票数  从0到n
	for(ll i = 0;i <= n; ++i)
	{
		memset(c,0x00,sizeof(c));
		memset(w,0x00,sizeof(w));
		
		//记录当前所买入的花费
		ll now = 0;
		//遍历所有选民
		for(ll j = n;j > 0; --j)
		{
		    //如果这个票是1号自己的,或者这个选民选的党派小于我们枚举1号党的最终选票
		    //就把他加上去
			if(w[v[j].first] < i || v[j].first == 1)
			{
				w[v[j].first]++;
			}
			else
			{   //否则就把它买了  标记已经买过   并且1号党的票数+1   加上相应的钱
				now += v[j].second,c[j] = 1,w[1]++;
			}
		}
		//想让1号党赢必须保证1号党的选票大于最多得票数  也就是 i
		for(ll j = 1;j <= n; ++j)
		{
			if(w[1] <= i && v[j].first != 1 && c[j] == 0)
			{
				now += v[j].second,c[j] = 1,w[1]++;
			}
		}
		//枚举的i  符合标准就记录花的钱  并找最小值
		if(w[1] > i)
		{
			ans = min(ans,now);
		}
	}
	cout<

 

至于D,,E

ε=ε=ε=┏(゜ロ゜;)┛

(感觉永远都在1500的水平了,菜逼)

你可能感兴趣的:(codeforces,ACM)