cf训练赛20190813

A. Little C Loves 3 II

题意:
给n * m的网格,每次可以选择距离为 ∣ x i − x j ∣ + ∣ y i − y j ∣ |x_i−x_j|+|y_i−y_j| xixj+yiyj 的两点标记,问最多可以标记多少个点。
解:
找规律题

关键点:n,m取(1,6)(2,4)(3,4)(2,5)时都能把整个网格全部标记完。
那么可以推得,当n,m为(奇,偶)(偶,偶) 时答案为n*m,即全部标记,而为(奇,奇)时,答案为 n * m - 1。[奇代表大于3的奇数,偶代表大于2的偶数]
证:
因为(1,6)可以完全标记,所以只要一边是6的倍数,另一边无论取几都能完全标记。
因为(3,3)(3,5)只有一个没标记,(3,4)(3,6)全标记,所以只要(3,偶>=4)一定可以由(3,4)(3,6)构成,一定全标记,而(3,奇>=5)一定可以由(3,3)和一个(3,偶>=4)构成,一定只有一个没标记。

当n为大于3的奇数,m为大于2的偶数。
m一定可以由若干个4,6构成,而n一定可以由若干个2,3构成。那么把方阵拆分成由4或其倍数和由6或其倍数构成的两部分,6的部分前面已证肯定能全部标记,而4的部分可以全都拆分为(2,4)(3,4)也可以全部标记,所以可以全部标记。
当n,m都为大于2的偶数。
n,m都一定可以由若干个4,6构成,与n奇m偶同理。
当n,m都为大于3的奇数。
而当n,m大于3,较大的奇数n一定可以拆分为一个3和一个偶数,(奇,偶)前面已证全标记,(3,奇)也已知只有一个没标记。

所以当n,m都大于等于3的时候直接根据奇偶输出n * m或者n * m-1,否则直接根据n=1,2,3分别计算。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll f[10]= {0,0,0,0,2,4};
ll ans[4][4]={0,0,0,0,0,0,0,0,0,0,0,4,0,0,4,8};
int main()
{
    ll n,m;
    while(cin>>n>>m)
    {
        ll mx=max(n,m);
        ll mi=min(n,m);
        if(n<=3&&m<=3)
        cout<<ans[n][m]<<endl;
        else if(n>=3&&m>=3)
        {
            if(n%2==0||m%2==0)cout<<n*m<<endl;
            else cout<<n*m-1<<endl;
        }
        else if(mi==1)
        {
            cout<<mx/6*6+f[mx%6];
        }
        else if(mi==2)
        {
            if(mx==4)cout<<n*m<<endl;
            else if(mx==5)cout<<n*m<<endl;
            else if(mx==6)cout<<n*m<<endl;
            else if(mx==7)cout<<12<<endl;
            else cout<<n*m<<endl;
        }
    }
}

B. Anton and Making Potions

题意:
求制作n瓶药的最小时间,已知每瓶药需要花费x时间。现在有两种魔法可以加快制药,最开始总共有魔力s,第一种魔法有m个,是把每瓶药花费时间变成 a i a_i ai,花费 b i b_i bi魔力,第二种魔法有k个,是直接生成 c i c_i ci个药,花费 d i d_i di魔力。每种魔法最多用一个。
解:
字多水题
直接暴力遍历第一种魔法的每一个,然后二分第二种魔法找到能用剩余的魔力制药最多的。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[200005],b[200005],c[200005],d[200005];
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    ll n,m,k,x,s;
    cin>>n>>m>>k>>x>>s;
    for(int i=1;i<=m;++i)
        cin>>a[i];
    for(int i=1;i<=m;++i)
        cin>>b[i];
    for(int i=1;i<=k;++i)
        cin>>c[i];
    for(int i=1;i<=k;++i)
        cin>>d[i];
    ll j=upper_bound(d+1,d+k+1,s)-d;
    ll ans=j!=1&&j<=k?(n-c[j-1])*x:j==1?n*x:(n-c[k])*x;
    for(int i=1;i<=m;i++)
    {
        if(b[i]<=s){
        j=upper_bound(d+1,d+k+1,s-b[i])-d;
        j=j>1&&j<=k?j-1:j<=1?0:k;
        ans=min(ans,(n-c[j])*a[i]);
        }
    }
    cout<<ans<<endl;
}

F. Knight Tournament

题意:n个人排成一列,每次给一个区间 【 L , R 】 【L,R】 L,R和一个 i ( L &lt; = i &lt; = R ) i(L&lt;=i&lt;=R) i(L<=i<=R),把这个区间内除了位置i和之前已经操作过的位置以外全都变成i,要求输出操作全部结束每个数是什么。
解:
我看到有用并查集做的,还有直接变换下标然后遍历,其实主题思路都差不多。

#include<bits/stdc++.h>
using namespace std;
int f[300005],a[300005];
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n,m,l,r,x,tmp;
    cin>>n>>m;
    for(int i=1; i<=n; i++)
        f[i]=i+1;
    for(int i=1; i<=m; i++)
    {
        cin>>l>>r>>x;
        for(int j=l; j<x; j=tmp)
        {
            tmp=f[j];
            if(!a[j])a[j]=x;
            f[j]=x;
        }
        for(int j=x+1; j<=r; j=tmp)
        {
            tmp=f[j];
            if(!a[j])
                a[j]=x;
            f[j]=f[r];
        }
    }
    for(int i=1; i<=n; i++)if(i!=n)cout<<a[i]<<" ";
        else cout<<a[i]<<'\n';
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值