每一年都奔走在自己热爱里

没有人是一座孤岛,总有谁爱着你

AtCoder Beginner Contest 236(D,E,F)

AtCoder Beginner Contest 236(D,E,F)

D

D

这道题的大意是有\(2n\)个数,我们可以让\(i\)\(j\)配对,且\(i<j\),那么这一对的值就是\(a[i] [j]\),他会给出所有可能出现的配对的方式的值,求出\(n\)对数得到的值的异或值最大的那一个

我之前是想过暴力,因为这个\(n\)小于\(8\),但是我的方向错了,我之前认为每一个数都有\(2n\)个可以和它配对,但是就以为是\({2n}^{2n}\),我就觉得会不会太大了,然后就没有深想了,现在想来真是太蠢了,脑子不太清醒,虽然方向不对,但是这个时间复杂度的预估也太离谱了,简直了

对于每一对,其实我们不用考虑那么多,其实总共就只有\(n\)对,所以较小的那一个,那么那个\(i\)我们其实可以顺其自然,后面那一个才是我们需要找的,这里可以用回溯的方式找出最合适的

这次确实是我想的太过于粗暴了,我以为每一个数要找一个和这个数匹配的数,我如果暴力的话(在不管大小的情况下)有\((n-1)^n\)种情况,就觉得这样就会超时

其实如果我们考虑的大小的关系,如果现在此时需要那个较小的数,那么此时还没有用到的最小的那一个一定是那个\(i\),所以我们其实可以确定此时的\(i\),然后再考虑比\(i\)大的数作为\(j\),这样处理就会使得时间复杂度降低

#include <iostream>
#include <vector>
using namespace std;
const int maxn=30;
#define int long long 
int g[maxn][maxn];
bool vis[maxn];
int ans,n;
void dfs(int cur,int cnt,int res)
{
    if (cnt==2*n)
    {
        ans=max(res,ans);
        return ;
    }
    if (cnt%2==0)
    {
        for (int i=1;i<=2*n;i++)
        {
            if (vis[i]) continue;
            vis[i]=true;
            dfs(i,cnt+1,res);
            vis[i]=false;
            return ;
        }
    }
    else 
    {
        for (int i=cur+1;i<=2*n;i++)
        {
            if (vis[i]) continue;
            vis[i]=true;
            int u=cur,v=i;
            dfs(i,cnt+1,res^g[u][v]);
            vis[i]=false;
        }
    }
    return ;
}
signed main ()
{
    cin>>n;
    for (int i=1;i<=2*n;i++)
    {
        for (int j=i+1;j<=2*n;j++)
        {
            cin>>g[i][j];
        }
    }
    ans=0;
    vis[1]=true;
    dfs(1,1,0);
    cout<<ans<<'\n';
    system ("pause");
    return 0;
}

E

E

学习

这个题大意是给你\(n\)个数,我们可以从这\(n\)个数选择一些数,但是对于\(1<=i<n\),对于这里面的每一个\(i\),我们都必须从\(i\)\(i+1\)的数至少选一个,然后我们需要满足上面条件的若干个数的最大中位数,最大平均值,这两个值的若干个数的选择是相互独立的

我之前想到好多种变化,这是我们自己构造不出来的(我构造不出来)

然后看了一些题解,万万没想到这个竟然可以用二分来写(我都没有想到这方面上)

那么二分的\(check\)函数应该怎么写呢

对于平均数,我们可以知道对于目前已经选择的数的和大于等于此时的\(x\)

这里我们要怎么选择呢

我们这里还定义了一个二维的\(f\)数组,\(f[i] [0]\)代表着从\(1到i\)并且我们不会选择\(a_i\)的情况,\(f[i] [1]\)代表着从\(1到i\)并且我们一定选择\(a_i\)的情况

那么我们就可以选择一下的转移方式

如果我们此时决定\(a_i\)的选择

如果不选,\(f[i] [0]=f[i-1] [1]\),那么它的前一位必须要选择

如果选,\(f[i] [1]=max(f[i-1] [1],f[i-1] [0])+a[i]\),那么它的前一位可选可不选

对于中位数,我们可以知道不比中位数小的数量要小于比中位数小的数多

具体的细节看代码

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn=1e5+10;
#define int long long 
#define eps 1e-6
int a[maxn],n;
bool check1(double x)
{
    vector<vector<double>>f(n+1,vector<double>(2));
    f[0][0]=f[0][1]=0;
    for (int i=1;i<=n;i++)
    {
        f[i][0]=f[i-1][1];
        f[i][1]=max(f[i-1][1],f[i-1][0])+a[i]-x;
    }
    return max(f[n][0],f[n][1])>=0;
}
bool check2(int x)
{
    vector<vector<int>>f(n+1,vector<int>(2));
    for (int i=1;i<=n;i++)
    {
        f[i][0]=f[i-1][1];
        f[i][1]=max(f[i-1][0],f[i-1][1])+(a[i]>=x?1:-1);
    }
    return max(f[n][0],f[n][1])>0;
}
signed main ()
{
    cin>>n;
    for (int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    double l=0,r=1e9;
    double ave=0;
    while (r-l>=eps)
    {
        double mid=(l+r)/2;
        if (check1(mid))
        {
            l=mid;
            ave=mid;
        }
        else r=mid;
    }
    int L=0,R=1e9;
    int midans=0;
    while (L<=R)
    {
        int mid=(L+R)>>1;
        if (check2(mid))
        {
            midans=mid;
            L=mid+1;
        }
        else R=mid-1;
    }
    cout<<ave<<'\n'<<midans<<'\n';
    system ("pause");
    return 0;
}

F

F

学习

这个题大意是有\(2^n -1\)个数,对于\(1\)\(2^n -1\)个数,我们如果需要从这些数中选择若干个数,让我们可以得到这若干个数的异或值可以变成\(1,2,3,4,...2……2^n -1\),如果我们要选择\(i\),那么会消耗\(a_i\)的价值,然后我们需要如果有若干个数的异或值可以变成\(1\)\(2^n -1\)的最小价值

这个是线性基的模板题

线性基

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn=2e5+10;
#define int long long 
int n,m;
signed main ()
{
    cin>>n;
    m=1<<n;
    vector<pair<int,int>>v;
    for (int i=1;i<m;i++)
    {
        int x;
        cin>>x;
        v.push_back({x,i});
    }
    sort(v.begin(),v.end());
    int ans=0;
    vector<int>t(n+1,0);
    for (auto [val,x]:v)
    {
        for (int i=0;i<n;i++)
        {
            if ((x>>i&1))
            {
                if (!t[i])
                {
                    ans+=val;
                    t[i]=x;
                    break;
                }
                else 
                {
                    x^=t[i];
                }
            }
        }
    }
    cout<<ans<<'\n';
    system ("pause");
    return 0;
}
posted @ 2023-02-09 20:12  righting  阅读(24)  评论(0)    收藏  举报