AtCoder Beginner Contest 318

目录

A - Full Moon

B - Overlapping sheets

C - Blue Spring

D - General Weighted Max Matching

E - Sandwiches

F - Octopus


A - Full Moon

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
typedef long long ll ;
const int maxv=4e6+5;
typedef pair<ll,ll> pll;
 


void solve()
{
    int n,m,p;
    cin>>n>>m>>p;
    if(m>n) cout<<0<<endl;
    else {
        n-=m;
        int ans=n/p;
        cout<<ans+1<<endl;
    }
}
 
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t=1;
	//cin>>t;
    while(t--){
        solve();
    }
    system("pause");
    return 0;
}

B - Overlapping sheets

一眼扫描线,感觉人都魔楞了

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
typedef long long ll ;
const int maxv=4e6+5;
typedef pair<ll,ll> pll;
 
int st[105][105];

void solve()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        int a,b,c,d;
        cin>>a>>b>>c>>d;
        for(int l=a+1;l<=b;l++){
            for(int r=c+1;r<=d;r++){
                st[l][r]=1;
            }
        }
    }
    int cnt=0;
    for(int i=0;i<105;i++){
        for(int j=0;j<105;j++){
            if(st[i][j]) cnt++;
        }
    }
    cout<<cnt<<endl;
}
 
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t=1;
	//cin>>t;
    while(t--){
        solve();
    }
    system("pause");
    return 0;
}

C - Blue Spring

思路:贪心,考虑购票乘车票的代价和直接购票的代价即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
typedef long long ll ;
const int maxv=4e6+5;
typedef pair<ll,ll> pll;
 
int st[105][105];

void solve()
{
    int n,d,p;
    cin>>n>>d>>p;
    vector<ll> a(n+5),s(n+5);
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a.begin()+1,a.begin()+1+n,greater<ll>());
    for(int i=1;i<=n;i++){
        s[i]=s[i-1]+a[i];
    }
    ll ans=1e18;
    for(int i=1;i<=n;i++){
        ll t=(i+d-1)/d;
        ll v=t*p;
        if(v<s[i]){
            ans=min(ans,v+s[n]-s[i]);
        }
    }
    ans=min(ans,s[n]);
    cout<<ans<<endl;
}
 
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t=1;
	//cin>>t;
    while(t--){
        solve();
    }
    system("pause");
    return 0;
}

D - General Weighted Max Matching

思路:搜索,思路和全排列搜索比较类似。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
typedef long long ll ;
const int maxv=4e6+5;
typedef pair<ll,ll> pll;
 

int n;

ll g[20][20];
int st[20];
ll res;
ll ans;
void dfs(int x)
{
    if(x>n){
        ans=max(ans,res);
        return ;
    }
    if(st[x]){
        dfs(x+1);
        return ;
    }
    for(int i=x+1;i<=n;i++){
        if(!st[i]&&!st[x]){
            st[i]=st[x]=1;
            res+=g[x][i];
            dfs(x+1);
            res-=g[x][i];
            st[i]=st[x]=0;
        }
    }
    dfs(x+1);
}



void solve()
{
    //int n;
    cin>>n;
    for(int i=1;i<=n-1;i++){
        for(int j=i+1;j<=n;j++){
            int w;
            cin>>w;
            //cout<<i<<" "<<j<<" "<<w<<" "<<endl;
            g[i][j]=w;
        }
    }
    dfs(1);
    cout<<ans<<endl;

}   
 
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t=1;
	//cin>>t;
    while(t--){
        solve();
    }
    system("pause");
    return 0;
}

E - Sandwiches

思路:因为要求a_ia_k相同,考虑a_j,使用桶去记录每个相同数字的下标,然后对每个数字进行枚举中间量a_j,对于中间量的枚举,如果我们对每个桶中的每个下标进行枚举,肯定会超时,考虑优化:我们发现,对于一个桶,我们计算到当前量j,那么其对答案的贡献为s_{j+1}-s_{j}+s_{j+2}-s_{j}+......+s_{s.size}-s_j,s表示a_j的个数,所以我们可以对这个前缀和再求一遍前缀和即可。

具体注释看代码。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
typedef long long ll ;
const int maxv=4e6+5;
typedef pair<ll,ll> pll;
typedef array<ll,3> p3;
const int mod=1e9+7;


vector<ll> mp[N];


void solve()
{
    int n;
    cin>>n;
    ll res=0;
    vector<int> a(n+5);
    for(int i=1;i<=n;i++){
        cin>>a[i];
        mp[a[i]].push_back(i);
    }
    for(int i=1;i<=n;i++){
        auto v=mp[i];
        vector<ll> b(v.size()+5),s(v.size()+5);
        for(int j=1;j<v.size();j++){
            int cur=v[j]-v[j-1]-1;
            b[j]=cur;//记录两个相同数之间的数字个数
        }
        for(int j=1;j<v.size();j++){
            s[j]=b[j]+s[j-1];//前缀和
        }
        vector<ll> ss(v.size()+5);
        for(int j=1;j<v.size();j++){
            ss[j]=ss[j-1]+s[j];//对前缀和再求一遍前缀和
        }
        int sz=v.size()-1;
        for(int j=0;j<v.size();j++){
            res+=ss[sz]-ss[j]-s[j]*(sz-j);//计算贡献
        }
    }
    cout<<res<<endl;



}   
 
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t=1;
	//cin>>t;
    while(t--){
        solve();
    }
    system("pause");
    return 0;
}

F - Octopus

思路:对于一个位置k,我们考虑其是否合法,贪心的去想,我们将坐标和k的绝对值按升序排序,若每一个l_i能和排序后的x_i一一对应(即其都在l_i的那个区间内)。但因为k所能选的点的范围为1e18,我们不能去一一枚举,那么我们就考虑去寻找区间。

在寻找区间前,我们考虑当位于k时合法,位于k+1时不合法的情况,那么我们会发现仅有$k_0=X_i+L_j$符合条件。

同样,我们考虑位于k时不合法,位于k+1合法的情况,仅有$k_0=X_i-L_j-1$。符合条件。

所以我们一共会得到2*n*n个点,我们去检查每个点是否合法即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
typedef long long ll ;
const int maxv=4e6+5;
typedef pair<ll,ll> pll;
typedef array<ll,3> p3;
const int mod=1e9+7;

int n;
vector<ll> x(205),l(205);

bool check(ll k)
{
    sort(x.begin()+1,x.begin()+1+n,[&](ll x,ll y){
        return abs(k-x)<abs(k-y);
    });
    for(int i=1;i<=n;i++){
        if(abs(k-x[i])>l[i]) return false;
    }
    return true;
}


void solve()
{
   // int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>x[i];
    }
    for(int i=1;i<=n;i++) cin>>l[i];
    vector<ll> s;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            s.push_back(x[i]+l[j]);
            s.push_back(x[i]-l[j]-1);
        }
    }
    sort(s.begin(),s.end());
    sort(l.begin()+1,l.begin()+1+n);
    ll ans=0;
    for(int i=1;i<s.size();i++){
        if(check(s[i])){
            ans+=s[i]-s[i-1];
        }
    }
    cout<<ans<<endl;


}   
 
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t=1;
	//cin>>t;
    while(t--){
        solve();
    }
    system("pause");
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值