7/24 训练日志

Posted 钟钟终

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了7/24 训练日志相关的知识,希望对你有一定的参考价值。

每日一题

D2. Chopping Carrots (Hard Version)
1.枚举极小值,其值存在上限,为数组a中最小的那个数,即为a[1];
2.无法如D1一般枚举a[i],数据范围改变,存在超时问题;
3.可改变思路:枚举p[i],范围是1~k。a[i]数组是单调不减的,根据极差值,可构造a[i]/p[i],使得大小存在递增关系;
4.通过枚举极差中的最小值,再枚举每一个p,再通过lower_bound查找数组a中的值;
5.若正好存在i*p==a[i],则找到;若大于数组a中最大值,则跳出;

#include <bits/stdc++.h>
#define int long long
#define endl '\\n'

using namespace std;
const int N=1e6+5;
int n,k,a[N];

signed main()

    int t;cin>>t;
    while(t--)
    
        cin>>n>>k;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        int mn=a[1],mx=a[n],ans=1e9;
        for(int i=1;i<=mn;i++)
        
            int res=0;
            for(int j=1;j<k;j++)
            
                int ai=i*(j+1);
                if(ai-i>mx)
                    break;
                int g=lower_bound(a+1,a+n+1,ai)-a-1;
                if(!g||a[g]<i*j)
                    continue;
                res=max(res,a[g]/j);
            
            if(a[n]>=i*k)
                res=max(res,a[n]/k);
            if(res>=i)
                ans=min(ans,res-i);
        
        cout<<ans<<endl;
    
    return 0;


思维

C. Recover an RBS
题意并不难理解,但思路也没那么好想。
三种符号'(' ')' '?',可想到左右括号是可以相互抵消的,而?是存在其中的变量。要用?来表示左右括号中较少的那个来达到平衡。确定的状态可进行消去,不确定的要进行保留,最后比较是否相等。

#include <bits/stdc++.h>
#define int long long
#define endl '\\n'

using namespace std;
const int N=1e6+5;
string s;

signed main()

    int t;cin>>t;
    while(t--)
    
        cin>>s;
        int a=0,b=0;
        for(int i=0;i<s.length();i++)
        
            if(s[i]=='?')
                b++;
            else if(s[i]=='(')
                a++;
            else if(s[i]==')')
                a--;
            if(a<0)
                a++,b--;
            if(a==0&&b==1)
                a++,b--;
        
        if(abs(a)==b)
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    
    return 0;


C. Mark and His Unfinished Essay

1.若用暴力截取字符串的方法肯定会超时。
2.用l[i]和r[i]记录每次添加区间的左端点和右端点;用tl[i]和tr[i]记录,将截取子串添加主串中时,左右端点值;
3.从后向前,用每次询问的x减去区间长度,最后锁定下标x在字符串中的位置。tl[i]-l[i]可知该段区间长度

#include <bits/stdc++.h>
#define int long long
#define endl '\\n'
#define ios ios::sync_with_stdio(false),cin.tie(0)
using namespace std;
const int N=1e6+100;
int n,c,q,l[N],r[N],tl[N],tr[N];
string s;
signed main()

    int t;cin>>t;
    while(t--)
    
        cin>>n>>c>>q;
        cin>>s;
        tl[0]=0,tr[0]=n;
        for(int i=1;i<=c;i++)
        
            cin>>l[i]>>r[i];
            tl[i]=tr[i-1]+1;
            tr[i]=tl[i]+(r[i]-l[i]+1)-1;
        
        while(q--)
        
            int x;cin>>x;
            for(int i=c;i>=1;i--)
                if(tl[i]<=x&&x<=tr[i])
                    x-=tl[i]-l[i];
            cout<<s[x-1]<<endl;
        

    
    return 0;


算法训练

牛客练习赛62 水灾

一句话题意:给一个 n 个节点 m 条带权边的无向连通图,有 q 次询问,每次询问图中 ki 个互不相同的点,选择一个数 x,然后将图中所有边权小于等于 x 的边删除。求当删除这些边后 ki 个点互不连通时,x 的最小值。

思路:
1.将小于等于x的边删除,x最小为多少=>可看出建立kruskral重构树将边权化为点权,建立最大生成树,从而建立出小根堆。
2.两个点的最近公共祖先删除,则两个点不再联通;即根据二叉树的性质,可知找出数组a中最大的子树根节点即可。
3.此时kruskal的每个子树是原图上保留边权不小于根节点权值的边(即为小根堆)后的极大连通子图。
—>对于询问时数组a中的值,若是暴力两两比较求lca得最大值会超时;
因此利用小根堆性质,相邻节点(在同一层)上节点比较,可得出最大值,复杂度O(K)

#include <bits/stdc++.h>
#define int long long
#define endl '\\n'
#define IOS ios::sync_with_stdio(false),cin.tie(0)
using namespace std;
const int N=1e6+100;
int n,m,q,a[N],f[N],tol,val[N],lev[N],level,tmp[N],lans;
vector<int>g[N];
bool vis[N];
struct node

    int x,y,z;
e[N];
bool cmp(node e1,node e2)

    return e1.z>e2.z;

int r_find(int r)

    if(r==f[r])    return f[r];
    f[r]=r_find(f[r]);
    return f[r];

int siz[N],dep[N],son[N],fa[N],top[N];
void dfs1(int u,int pare)   //重构树lca初始化

    siz[u]=1;dep[u]=dep[pare]+1;
    son[u]=0;fa[u]=pare;
    lev[u]=++level;
    for(auto &v:g[u])
    
        if(v!=pare)
        
            dfs1(v,u);
            siz[u]+=siz[v];
            if(siz[son[u]]<siz[v])
                son[u]=v;
        
    

void dfs2(int u,int topf)

    top[u]=topf;
    if(son[u])
        dfs2(son[u],topf);
    for(auto &v:g[u])
    
        if(v!=fa[u]&&v!=son[u])
            dfs2(v,v);
    

int lca(int x,int y)

    while(top[x]!=top[y])
    
        if(dep[top[x]]<dep[top[y]])
            swap(x,y);
        x=fa[top[x]];
    
    return dep[x]<dep[y]?x:y;


void kruskal()

    for(int i=1;i<n*2;i++)
        f[i]=i;
    sort(e+1,e+m+1,cmp);
    tol=n;
    for(int i=1;i<=m;i++)
    
        int fx=r_find(e[i].x),fy=r_find(e[i].y);
        if(fx!=fy)
        
            val[++tol]=e[i].z;
            f[fx]=f[fy]=tol;
            //g[fx].push_back(tol);
            g[tol].push_back(fx);
            //g[fy].push_back(tol);
            g[tol].push_back(fy);
            if(tol ==n*2-1) break;
        
    
    for(int i=1;i<=tol;i++)
    
        if(!siz[i])
        
            int rt=r_find(i);
            dfs1(rt,0);
            dfs2(rt,rt);
        
    

bool cmp1(int a,int b)return lev[a]<lev[b];

signed main()

    IOS;
    cin>>n>>m>>q;
    for(int i=1;i<=m;i++)
        cin>>e[i].x>>e[i].y>>e[i].z;
    kruskal();
    while(q--)
    
        int ans=0;
        int k;cin>>k;
        for(int i=1;i<=k;i++)
            cin>>tmp[i],tmp[i]^=lans;
        sort(tmp+1,tmp+k+1,cmp1);
        for(int i=2;i<=k;i++)
            ans=max(ans,val[lca(tmp[i],tmp[i-1])]);
        cout<<ans<<endl;
        lans=ans;
    
    return 0;


P1776 宝物筛选

直接套用模板会超时,可观察到件数达到1e5次方,因此使用二进制差分转化为01背包

#include <bits/stdc++.h>

using namespace std;
const int maxn=1e5+5;
int n,w,v[maxn],c[maxn],f[maxn];

int main()

    int cnt=1;
    scanf("%d%d",&n,&w);
    for(int i=1;i<=n;i++)    
    
        int x,y,z;scanf("%d%d%d",&x,&y,&z); 
        int t=1;
        while(z>=t)
        
           v[cnt]=x*t;
           c[cnt++]=y*t;
           z-=t;
           t<<=1;
        
        if(z)
        
            v[cnt]=x*z;
            c[cnt++]=y*z;
        
    
    cnt--;
    for(int i=1;i<=cnt;i++)
    
        for(int j=w;j>=c[i];j--)
        
            f[j]=max(f[j],f[j-c[i]]+v[i]);
        
    
    cout<<f[w]<<endl;
    return 0;


以上是关于7/24 训练日志的主要内容,如果未能解决你的问题,请参考以下文章

8/2 训练日志(dp+思维+字典树)

2017 全国多校第十场 训练日志

2022/7/22 训练日志

2017 全国多校第九场 训练日志

2018湖南多校第八场 训练日志

「训练日志17」 (8.12) 崩盘