雅礼学习10.5

雅礼学习10.5

上午考试

各题状况

T1

模拟挂成\(10\)分??

每次更新答案的时候位置搞错了。

想到了可能是线段树动态开点,但没写出来,因为标记下传不会。。。

T2

理解错了题目含义。

选出的\(m\)个物品中,至少要有\(k\)个是\(A\)喜欢的,至少\(k\)个是\(B\)喜欢的

那么很显然只要满足了上面的限制条件,俩人都不喜欢的也能选。。。

但考场上没想到这层

就凉了

正解变骗分,\(15\)分

T3

搞完上面两个题目之后没剩多少时间,就随便扔了个东西上去。。

也不知道写的是个啥

题目及考场代码

T1


/*
 * 第一眼感觉是线段树
 * 想了想,感觉线段树太浪费了,bitset应该可以搞
 * 但是。。。看了数据之后
 * 长度为10^18的01序列
 * 这。。做个头啊做。
 *
 * 第三种操作是0变1,1变0
 *
 * 对于n,m<=1000的数据,可以模拟
 * 对于只有1操作的情况,考虑维护全0区间和全1区间的分界点
 * 对于只有1,2操作的情况,因为是强制变成0或1,所以同样只考虑分界点
 * 对于n<=10^5的情况,线段树应该可以?但是不会维护。
 */
#include <cstdio>
#include <algorithm>

inline long long read()
{
    long long n=0;int w=1;register char c=getchar();
    while(c<'0' || c>'9'){if(c=='-')w=-1;c=getchar();}
    while(c>='0' && c<='9')n=n*10+c-'0',c=getchar();
    return n*w;
}

const int M=1e5+1,qwq[]={0,0,1};
int a[100001],ty[M];
long long l[M],r[M];
std::pair<int,int> pr[M];

int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);

    int m,flag=0;long long n=0;
    m=read();
    for(int i=1;i<=m;++i)
    {
        ty[i]=read(),l[i]=read(),r[i]=read();
        n=std::max(n,r[i]);
        flag=std::max(flag,ty[i]);
    }
    if(flag==1)
    {
        int id=1,cnt=0;
        for(int i=1;i<=m;++i)
        {
            if(l[i]<=id && r[i]>=id)
            {
                int x=r[i]+1;
                for(int j=1;j<i;++j)
                    if(l[j]<=x && r[j]>=x)
                        x=r[j]+1;
                id=x;
            }
            printf("%d\n",id);
        }
    }
    else
        if(n<=100000)
        {
            int id=1;
            for(int x,i=1;i<=m;++i)
            {
                if(ty[i]!=3)
                {
                    x=(ty[i]==1?1:0);
                    for(int j=l[i];j<=r[i];++j)
                        a[j]=x;
                }
                else
                    for(int j=l[i];j<=r[i];++j)
                        a[j]^=1;
                if(l[i]<=id && id<=r[i])
                {
                    for(;l[i]<=r[i];++l[i])
                        if(!a[l[i]])
                        {
                            id=l[i];
                            break;
                        }
                }
                printf("%d\n",id);
            }
        }
        else
            while(m--)
                puts("1");

    fclose(stdin),fclose(stdout);
    return 0;
}

T2

/*
 * 分成两人都喜欢的,只有A喜欢的,只有B喜欢的
 * 然后枚举从两个人都喜欢的物品里面选k个最便宜的
 * 然后贪心选剩下的部分
 *
 * 大样例跑不出来。。
 */
#include <cstdio>
#include <algorithm>

inline int read()
{
    int n=0,w=1;register char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    while(c>='0'&&c<='9')n=n*10+c-'0',c=getchar();
    return n*w;
}

const int N=2e5+1;
int n,m,k,a[N],b[N],v[N],both[N];
/*
int aaa,bbb;
void dfs(int now,int step,int aa,int bb)
{
    if(aa>k || bb>k)return ;
    if(step==m)
    {
        if(aa==k && bb==k)
            ++ans;
        return ;
    }
    if(aaa==now)
    {
        ++aaa;
        if(bbb==now)
        {
            ++bbb;
            dfs(now+1,step+1,aa+1,bb+1);
            dfs(now+1,step,aa,bb);
            --bbb;
        }
        else
        {
            dfs(now+1,step+1,aa+1,bb);
            dfs(now+1,step,aa,bb);
        }
        --aaa;
    }
    else
        if(bb==now)
        {
            ++bbb;
            dfs(now+1,step+1,aa,bb+1);
            dfs(now+1,step,aa,bb);
            --bbb;
        }
}
*/
inline bool cmp(const int &x,const int &y)
{return v[x]<v[y];}

int main()
{
    freopen("b.in","r",stdin);
    freopen("b.out","w",stdout);

    n=read(),m=read(),k=read();
    for(int i=1;i<=n;++i)
        v[i]=read();
    int aa=read(),bb;
    for(int i=1;i<=aa;++i)
        a[i]=read();
    bb=read();
    for(int i=1;i<=bb;++i)
        b[i]=read();

    std::sort(a+1,a+1+aa);
    std::sort(b+1,b+1+bb);
//哪些俩人都喜欢
    int aaa=1,bbb=1,emp=0;
    while(aaa<=aa && bbb<=bb)
    {
        if(a[aaa]>b[bbb])
            ++bbb;
        else
            if(a[aaa]<b[bbb])
                ++aaa;
            else
            {
                both[++emp]=a[aaa];
                ++aaa,++bbb;
            }
    }
/*
    for(int i=1;i<=emp;++i)
        printf("%d ",both[i]);
*/
//
    std::sort(both+1,both+1+emp,cmp);
    long long ans=0;
    for(int i=1;i<=k;++i)
        ans+=v[both[i]];

    if(emp>k)
    {//先把都喜欢的减掉
        m-=k;
        k=0;
    }
    else
    {
        m-=emp;
        k-=emp;
    }
//判断剩下的是不是够
    if(m<(k<<1))
    {
        printf("-1");
        fclose(stdin);fclose(stdout);
        return 0;
    }

    int cnt=1;emp=0;
    for(int i=1;i<=aa;++i)
    {
        if(a[i]!=both[cnt])
            a[++emp]=a[i];
        else    ++cnt;
    }
    aa=emp;
    cnt=1,emp=0;
    for(int i=1;i<=bb;++i)
    {
        if(b[i]!=both[cnt])
            b[++emp]=b[i];
        else    ++cnt;
    }
    bb=emp;

    if(k>aa || k>bb)
    {
        printf("-1");
        fclose(stdin);fclose(stdout);
        return 0;
    }

/*
    for(int i=1;i<=aa;++i)
        printf("%d ",a[i]);
    puts("");
    for(int i=1;i<=bb;++i)
        printf("%d ",b[i]);
*/

    std::sort(a+1,a+1+aa,cmp);
    std::sort(b+1,b+1+bb,cmp);
//然后贪心选剩下的
    for(int i=1;i<=k;++i)
        ans+=v[a[i]]+v[b[i]];
    int i=k+1,j=k+1;
    while(i+j<m)
    {
        if(v[a[i]]>v[b[j]])
            ans+=v[b[j++]];
        else    ans+=v[a[i++]];
    }
    printf("%lld",ans);

    fclose(stdin);fclose(stdout);
    return 0;
}

T3


#include<cstdio>
#include<iostream>
#include<fstream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define Set(a) memset(a,0,sizeof(a))
#define F(i,a,b) for(int i=a;i<=b;++i)
#define UF(i,a,b) for(int i=a;i>=b;--i)
#define openf(a) freopen(#a".in","r",stdin);freopen(#a".out","w",stdout)
typedef long long LL;
typedef long long ll;
typedef unsigned long long ULL;
typedef unsigned long long ull;

const int maxn=400+10;
const int maxm=5e4+10;
ll n,m;
ll u[maxm],v[maxm];
bool used[maxn],a[maxn][maxn];
ll f[maxn],xx;
ll tt;
void check()
{
    xx=0;
    Set(f);
    F(i,1,n) if(!used[i]) f[++xx]=i;
    F(i,1,xx)
    F(j,1,i)
    if(f[i]!=f[j]&&!a[f[i]][f[j]]) {a[f[i]][f[j]]=1;++tt;}
}
void dfs(int step)
{
    if(step==m+1) check();
    ll u1=u[step],v1=v[step];
    if(!used[u1]&&!used[v1]){used[u1]=1;dfs(step+1);used[u1]=0;used[v1]=1;dfs(step+1);used[v1]=0;}
    if( used[u1]&&!used[v1]){used[v1]=1;dfs(step+1);used[v1]=0;}
    if(!used[u1]&& used[v1]){used[u1]=1;dfs(step+1);used[u1]=0;}
    if( used[u1]&& used[v1])dfs(step+1);
    return;
}
int main()
{
    openf(c);
    scanf("%d%d",&n,&m);
    F(i,1,m) scanf("%d%d",&u[i],&v[i]);
    Set(used);
    Set(a);
    dfs(1);
    printf("%lld",tt);
    return 0;
}

正解及代码

T1

离散化线段树

对每个区间,维护一个\(tag\),维护的是最左边的\(0\)和最左边的\(1\)的位置

那么\(1\)操作就是把这个区间的\(tag\)变成区间左端点

然后考虑标记下传

\(1\)操作\(+\)任意操作还是\(1\)操作

\(2\)操作\(+\)任意操作还是\(2\)操作

\(3\)操作\(+1\)操作变成\(2\)操作

\(3\)操作\(+2\)操作变成\(1\)操作

\(3\)操作\(+3\)操作变成没有操作

然后直接离散化+线段树就行了,不需要动态开点

T2

把所有的物品分成:两人都喜欢的,\(A\)喜欢的,\(B\)喜欢的,都不喜欢的

枚举两人都喜欢的物品选了多少个(假设是\(x\)),那么再在\(A\)喜欢的物品中和\(B\)喜欢的点钟至少都还要选\(k-x\)个(用贪心的思路想,这里显然要选权值前\(k-x\)小的那些),然后如果还是没有选够\(m\)个,就在两人都不喜欢的物品中选最小的那些直到满足条件

那么从小到大枚举\(x\),不停求和就行了

T3

对这个问题,考虑一个更一般的问题:假设\(f_k(S)=f_{k-1}(S\cup \{v_i\})\)表示\(k\)个人来过之后,\(S\)集合内的苹果都还存活的概率是否\(\gt 0\),讨论得到三种情况

  • \(u_k,v_k\)都在\(S\)中,那么\(f_k(S)=0\)(两者至少要吃掉一个,所以\(S\)集合内的苹果不可能都剩下)
  • \(u_k,v_k\)有一个在\(S\)中,假设是\(u_k\)在\(S\)中,那么\(f_k(S)=f_{k-1}(S\cup \{v_i\})\)
  • \(u_k,v_k\)都不在\(S\)中,那么\(f_k(S)=f_{k-1}(S)\)

那么现在将所有的\(f_m(\{p\})=1\)都求出来,顺便求出\(g(p)\)是从\(f_m(\{p\})\)运行上面算法得到的最终集合

观察得到\((u,v)\)合法的条件就是\(f_m(\{u\})=1,f_m(\{v\})=1,g(u)\cap g(v)=\varnothing\)

直接枚举,即可得到答案

下午讲课:树上的题

例1

给定一棵\(n\)个节点的树,你可以进行\(n?1\)次操作,每次操作步骤如下:

  • 选择\(u,v\)两个度数为\(1\)的节点。
  • 将\(u,v\)之间的距离加到\(ans\)上。
  • 将\(u\)从树上删除。

求一个操作序列使得\(ans\)最大。

解:

先把直径拿出来,将直径外的点一个一个的和直径中的某一个端点配对并删掉,最后再将直径删掉。

证明:

如果当前直径外已经没有点了,那么显然只能将直径的端点删掉;否则一定不会去删直径的端点。
因为先删一个直径外的点再删直径端点一定是不劣于先删直径端点再删这个直径外的点的。

比如有这样三个点\(x,y,z\),\(x,z\)是该树直径的两端,

假设删除顺序是\(x,y\),那么\(ans+=dis[x][z]+dis[y][z]\)

假设删除顺序是\(y,x\),那么\(ans+=\max(dis[x][y],dis[y][z])+dis[x][z]\)

例2

给定一张\(n\)个点\(m\)条边的带权无向联通图,\(q\)次询问,每次询问\(u_i\)到\(v_i\)的最短路长度

\(n,q\le 10^5,m-n\le 20\)

解:

注意到\(m-n\le 20\),那么这张图其实就是一个树多了屈指可数的几条非树边

先随便搞一棵生成树,那么会有几条边不在这个生成树上,标记那些有非树边连接的点

那么被标记的点最多\(40\)个,先跑\(40\)遍单源最短路求出这些被标记的点到其余所有点的最短路

对于一个询问,如果最短路(跑\(LCA\)来求)只经过生成树上的边,那么直接计算;若经过了被标记的点,就查看走这个点连接的非树边是否会对答案造成影响,尝试更新就行了

例3

给定一棵\(n\)个节点的树,定义叶子是度数为\(1\)的节点,点集\(S\)是好的如果满足任意两个\(S\)中的点之间的距离\(\le k\),现在要求将所有叶子分成若干不相交的好的集合,请问最少分成多少个好的集合。

\(n,k\le 10^6\)

解:

讲师说这类题目一般都可以贪心,我也不知道是哪类题目。。。(话说树上题目有什么分类的么orz)

先随便选一个根,方便起见选一个不是叶子的根,然后可以自底向上贪心。

设\(f_p\)表示\(p\)为根的子树内已完成的好的集合的数量,\(g_p\)表示未完成的集合中离\(p\)最远的叶子的距离。

考虑如何计算\(f_p\)和\(g_p\)。

首先将所有儿子的\(f\)先求和,然后将所有儿子的\(g\)排序,检查 一下最大的\(g\)和次大的\(g\)相加是否大于\(k\),如果大于,那么就将最大的\(g\)删掉,并把\(f_p\)加上\(1\)。否则就令\(g_p\)等于最大的\(g+1\)。

例4

给定\(n\)个节点,每个节点上有一个数字,要求用这些节点构建一棵二叉搜索树,满足有边相邻的两个节点上的数字互质
\(n\le 600\)

解:
先排序,令\(f[i][j][k]\)表示第\(i\)个点到第\(j\)个点以\(k\)为根是否可行
转移的时候首先检查是否存在\(u\in [i,k-1]\)满足\(f[i][k-1][u]=1\)且\(u\)上的数字跟\(k\)上的数字互质
右侧同理,检查是否存在\(v\in [k+1,j]\)满足\(f[k+1][j][v]=1\)且\(v\)上的数字跟\(k\)上的数字互质

但是这样是\(O(n^4)\)的(数组是\(n^3\)的,转移是\(n\)的)
考虑优化:
注意到上面的做法有一些重复运算。于是设\(L[i][j]\)表示是否存在\(k\in [i,j]\)满足\(f[i][j][k]=1\)且\(k\)上的数字和\(j+1\)上的数字互质,类似地定义\(R[i][j]\)

原文地址:https://www.cnblogs.com/kuaileyongheng/p/9746548.html

时间: 2024-08-29 06:07:18

雅礼学习10.5的相关文章

雅礼学习10.2

雅礼学习10.2 上午考试解题报告 各题状况(爆零) T1 想了10多分钟,暴力只有一个极大复杂度的想法,显然不可过,但还是写了,然后就全TLE也是...意料之中 T2 暴力很好写,但是错误理解了Tim给的部分分的意思:先给了一个\(a_i\le 10^9\),然后部分分里面没有提到\(a_i\)的情况,我就忽略了\(a_i\)的大小对答案统计的影响... 换句话说,我当时要是写了离散化,就是\(43\)分到手. T3 题目要求的输出可以分成三个问题,第一个问题正确 的话可以得到这个点的\(25

雅礼学习10.4

雅礼学习10.4 上午考试 各题状况 T1 莫名其妙20分了. 考场上一眼秒掉了这个题目:这不就是个并查集捆绑+快速幂么 然后开开心心这个点如果有这个质因子的话\(fa\)就指向这个质因子,而每个数字有多个质因子... 多个质因子在相互指\(fa\)的时候指乱套了.... 对拍的时候看出来的,然后用\(1\)个多小时来调这份代码,最后自己都不知道这东西在干嘛了,就凉了. T2 写了个暴力枚举,期望\(20\)实际\(20\) T3 看到成绩之后:这题怎么会爆\(long long\)的??? 然

雅礼学习10.7

雅礼学习10.7 上午考试 各题状况 全TM神仙题... \(T1\) \(35\)分暴力 \(T2\) 我\(n=1\)的时候直接输出了\(1\),连这个格子上是否有方块都没判,当时是感觉...难道这个部分分也会卡么 结果出题人就这么卡了..就一分都没有了 太毒瘤了. \(T3\) 成功骗\(8\)分 做了一段时间之后去做牛客网的来着. 跟人要了份暴力 然后我TM..从紫名变成灰名了???? 题目及考场代码 T1 /* * 暴力思路:从初始位置开始进行bfs */ #include<queue

雅礼学习10.6

雅礼学习10.6 上午考试 各题状况 T1 二分答案 应该有反例,就是说,答案应该不是单调的 但是不会写其他的算法了啊... T2 我TM... 第二个红框圈出来的部分应该是 if(x1+x1!=s) 写错了,就没了\(18\)分.. T3 写了个\(n^4\)的暴力 最后发现题目中的矩形的四个顶点不一定是给定的顶点.. 那就GG了 各题题目及考场代码 T1 /* * 二分答案.. * 复杂度O(20(N+NlogN+M))的,感觉很悬 * 排序应该可以优化掉,但是不太会哎. */ #inclu

雅礼学习10.3

各题状况 T1 暴力修改+一维差分+二维差分 莫名其妙就没了49分... 好像是数组开的不够大? T2 这...概率和期望,一会不会,连那个一分的部分分都没有任何思路 T3 题目并没有看太懂.. 写了一个枚举算法,然后对某个一分的数据输出显然的结果 ... 然后就只拿了1分 枚举挂了,因为会错了题目含义 题目及考场代码 T1 /* * 一个个修改肯定超时.. * q==0的直接输出0 * 19分应该是暴力 * * 考虑对每次操作,计算一共修改了多少个位置 * 奇数个的话就让当前答案异或这个数字

#6030. 【雅礼集训 2017 Day1】矩阵

#6030. 「雅礼集训 2017 Day1」矩阵 题目描述 有一个 n×n  的矩阵,每个位置 (i,j) 如果是 . 表示为白色,如果是 # 表示为黑色. 初始时,每个位置可以是黑色或白色的,(i,j)  位置的值会作为 ai,j 给你. 现在有一种操作,选择两个整数 i,j∈[1,n],记 (i,1),(i,2),…,(i,n) (i, 1), (i, 2)的颜色为 C1,C2,…Cn ??,将 (1,j),(2,j),…,(n,j)  的颜色赋为 C1,C2,…,Cn ??. 你的任务是

2017雅礼省选集训做题记录

嘛,最近在补雅礼省选前集训的题.都是我会做的题..那一定是最水的那些题啦 题目在loj.ac上都有.过段时间如果搬了雅礼NOI集训的题应该也会做做的吧.. Day1 T1 一道经典套路题,做法跟UOJ #228基础数据结构练习题类似. 使用线段树维护.考虑相邻两个数的差值最多变化log次.也就是说,对于每个区间,只要操作二进行大概log次就能使得这个区间内所有数完全一样.所以对于操作二,只要记录一下区间最大最小值,就能直接打标记或者暴力DFS下去. 和UOJ那个题一样,注意一个特殊情况,就是一个

2018雅礼 折射

雅礼题好难啊. 这个DP题思路好强. 这个东西首先一眼就知道按y排的DP怎么写,大概就是设$f(i,j,k)$表示考虑到y坐标从大到小排名为i的点,这线上一次转是j,上上次转是k的数量,直接二维限制转移就行了. 考虑这东西怎么优化. 前缀和能搞时间,woc空间也被卡了??? 打出来表看一看???? 这个DP数组有好多都是空的... 因为越往后x限制的越少. 然后我就不会了. 正经:设$f(i,0/1)$表示从x坐标排名为i,出门左转还是右转的线的数量. 我一开始就否掉了这东西因为好像转移顺序会出

c 函数及指针学习 10

标准库函数 1算数运算stdlib.h 2随机数stdlib.h 3字符串转化stdlib.h 4数学函数 math.h 5日期和时间 time.h 6信号 signal.h 7打印可变参数列表stdarg.h 8断言 assert.h 抽象数据类型在数据结构中比较仔细 运行时环境没看 来自为知笔记(Wiz)c 函数及指针学习 10,码迷,mamicode.com