AtCoder #ABC 245

A Good morning(模拟)

过水

void solve()
{
    int h1, m1, h2, m2;
	cin >> h1 >> m1 >> h2 >> m2;
    if(h1 == h2)
    {
        if(m1 == m2)    puts("Takahashi");
        else if(m1 < m2)    puts("Takahashi");
        else puts("Aoki");
    }
    else if(h1 < h2) puts("Takahashi");
    else puts("Aoki");
}

B Mex(模拟)

过水

void solve()
{
	int n, x;
    cin >> n;
    for(int i = 0; i < n; i++)
        cin >> x, mp[x] = 1;
    
    for(int i = 0; i <= 2000; i++)
        if(mp[i] == 0)  {cout << i << endl; return;}
}

C Choose Elements(DP)

Description:

给定两个数组 a, b
要求构造出一个数组X满足以下要求 
1  X_i = a_i || X_i = b_i
2  abs(X_i - X_i+1) <= k

Solution:

​ 那我们很容易可以想到 这题就是对于当前的i去枚举一下i + 1的两条路是否能够走通

​ 画出一条搜索树 可以得知DFS复杂度 2^n

​ 那我们就考虑一下在搜索的过程中 我们做了那些无用功导致复杂度那么高

​ 简单判断 当一个点不可达的时候 这个点就已经无效了 不需要用它向后拓展了

​ 然后想办法记录当前状态 递推并用bool数组记录下是否可达 最后询问终点的状态即可

​ 那么一个状态DP的雏形就出现了 对于每一个可达点 我们去判断他的下一步的两个点是否可达

Code:

const int N = 200010;
int a[N], b[N];
bool dpa[N], dpb[N]; //a[i]是否可达 b[i]是否可达
 
void solve()
{
	int n, k;
    cin >> n >> k;
    for(int i = 1; i <= n; i++)
        cin >> a[i];
    for(int i = 1; i <= n; i++)
        cin >> b[i];
    
    dpa[1] = true;
    dpb[1] = true;
 
    for(int i = 1; i <= n - 1; i++)
    {
        if(dpa[i])
        {
            if(abs(a[i + 1] - a[i]) <= k)   dpa[i + 1] = true;
            if(abs(b[i + 1] - a[i]) <= k)   dpb[i + 1] = true;
        }
        if(dpb[i])
        {
            if(abs(a[i + 1] - b[i]) <= k)   dpa[i + 1] = true;
            if(abs(b[i + 1] - b[i]) <= k)   dpb[i + 1] = true;
        }
    }
 
    if(dpa[n] || dpb[n])    cout << "Yes" << endl;
    else cout << "No" << endl;
}

D Polynomial division(多项式除法 + 模拟)

Description:

​ 给出两个多项式 求其商

Solution:

​ 模拟竖式计算 重要的是因为小心/0的情况

Code:

void solve()
{
	int n, m;
	cin >> n >> m;
	vector<int> a(n + 1), c(n + m + 1), b(m + 1);
	for(int i = 0; i <= n; i++)
		cin >> a[i];
	for(int i = 0; i <= n + m; i++)
		cin >> c[i];
	
	for(int i = m; i >= 0; i --) //枚举b的同时也是枚举c的[n + 1, c + m + 1]
	{
	    b[i] = c[n + i] / a[n];
	    for(int j = 0; j <= n; j++)
	        c[i + j] -= b[i] * a[j];
 	}
	for(auto x : b) cout << x << ' ';
	cout << endl;
}

E Wrapping Chocolate(排序 + 二分)

Description:

​ 给出n个巧克力 m个盒子 当盒子的长和宽都大于等于巧克力的时候(长和宽不能颠倒) 可以装下巧克力 请问是否能装下所有的巧克力

Solution:

​ 因为N=2e5 应该是要用一个nlog的做法过掉 然后又跟大小有关系 于是我就打算往排序想

​ 对巧克力和盒子都小到大排序 然后双指针判断 然后一直写挂

​ 总感觉应该是枚举漏了情况 思维不够紧密

​ 正解是 以宽大到小排序 用multiset存下 宽大于等于当前巧克力的box 然后在集合里二分查找第一个长度大于等于巧克力长度的盒子 若找不到 证明后面当前巧克力无法放入任何盒子中 失败

Code:

void solve()
{
	int n, m;
    cin >> n >> m;
 
    vector<array<int,2> > box(m), a(n);
    for(int i = 0; i < n; i++)
        cin >> a[i][0];
    for(int i = 0; i < n; i++)
        cin >> a[i][1];
    for(int i = 0; i < m; i++)
        cin >> box[i][0];
    for(int i = 0; i < m; i++)
        cin >> box[i][1];
 
    sort(a.begin(), a.end(), greater());
    sort(box.begin(), box.end(), greater());
 
    multiset<int> s; //存长度
    for(int i = 0, j = 0; i < n; i ++) //遍历巧克力
    {
        while(j < m && box[j][0] >= a[i][0]) //当宽度大于等于当前巧克力
        {
            s.insert(box[j][1]);
            j ++;
        }
        auto it = s.lower_bound(a[i][1]);
        if(it == s.end())   //因为在当前大于等于巧克力宽度的box里都找不到了 那后面更找不到
        {
            cout << "No\n";
            return;
        }
        s.erase(it);
    }
    cout << "Yes\n";
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值