EZ 2018 05 06 NOIP2018 慈溪中学集训队互测(五)

享受爆零的快感

老叶本来是让初三的打的,然后我SB的去凑热闹了

TM的T2写炸了(去你妹的优化),T1连-1的分都忘记判了,T3理所当然的不会

光荣革命啊!

T1

思维图论题,CHJ dalao给出了正解但-1输成0了缅怀

而且这题不能用读优玄学

思路也很新奇,先跑一遍MST,判断是否有无解的情况

然后看一下MST中与1相连的边有几条

如果小于k那么我们把所有与1相连的边减上一个值使它们优先被选,然后跑MST

大于k就加上去即可

注意到这个值可以二分,因此不停做MST即可

CODE

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=5005,M=100005;
const double EPS=1e-5;
struct data
{
    int l,r,s;
    double add;
}a[M];
int n,m,k,cnt,father[N],tot;
long long ans;
inline bool comp(data a,data b)
{
    return a.s+a.add<b.s+b.add;
}
inline int getfather(int k)
{
    return father[k]==k?k:father[k]=getfather(father[k]);
}
inline int MST(double x)
{
    register int i; int res=0,tot=0;
    for (i=1;i<=m;++i)
    if (a[i].l==1||a[i].r==1) a[i].add=x;
    sort(a+1,a+m+1,comp);
    for (i=1;i<=n;++i)
    father[i]=i; ans=0;
    for (i=1;i<=m;++i)
    {
        int fx=getfather(a[i].l),fy=getfather(a[i].r);
        if (fx!=fy)
        {
            if (a[i].l==1||a[i].r==1) ++res;
            ans+=a[i].s; ++tot;
            father[fx]=fy;
        }
    }
    if (tot!=n-1) return -1;
    return res;
}
int main()
{
    freopen("path.in","r",stdin); freopen("path.out","w",stdout);
    register int i;
    scanf("%d%d%d",&n,&m,&k);
    for (i=1;i<=m;++i)
    {
        scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].s);
        if (a[i].l==1||a[i].r==1) ++tot;
    }
    if (tot<k||MST(0)==-1) { puts("-1"); return 0; }
    double l=-100000.0,r=100000.0;
    while (r-l>EPS)
    {
        double mid=(l+r)/2.0;
        int t=MST(mid);
        if (t==k) { printf("%lld",ans); break; }
        if (t>k) l=mid; else r=mid;
    }
    return 0;
}

T2

这么小的数据范围,就是套路的状压DP

只有我一个人想到记忆化搜索暴力玄学搜索么

好吧又是我ZZ了

首先发现n的范围只有15,果断状压成01串表示第几个串选或不选

而后预处理一个数组g[i][j]表示当t[i]上的字符为j时,与其它串的匹配情况(用二进制下压缩01串表示)

例如,四个串为

?a?

ab?

aa?

??b

例如

  • g[2][‘a‘]=1101(与第四个,第三个,第一个串分别匹配)=13
  • g[1][‘a‘]=1111=15

然后我们设DP数组f[i][j]表示匹配到第i位时(第i位尚未匹配)所有串的匹配情况为j(二进制下的01串)时方案总数

则有f[i][j]可以转移出

f[i+1][j&g[i][ch]]+=f[i][j](‘a‘<=ch<=‘z‘)

因为这里只要一个位置不匹配那就整个串都不匹配,因此只有两边都是1才满足要求

最后ans+=所有j的1的个数恰好为k个的f[len+1][j]

C++没有以字符为下标的数组,因此所有字符减去‘a‘即可

CODE

#include<cstdio>
#include<cstring>
using namespace std;
const int N=20,D=50,mod=1000003;
int g[D+5][30],f[D+5][(1<<N+1)+5],n,k,ans,t;
char s[N][55],ch;
inline int count(int x)
{
    int tot=0;
    while (x) tot+=x&1,x>>=1;
    return tot;
}
int main()
{
    freopen("question.in","r",stdin); freopen("question.out","w",stdout);
    register int i,j; scanf("%d",&t);
    while (t--)
    {
        memset(f,0,sizeof(f));
        memset(g,0,sizeof(g));
        scanf("%d%d",&n,&k);
        for (i=1;i<=n;++i)
        scanf("%s",s[i]+1); int len=strlen(s[1]+1);
        for (i=1;i<=len;++i)
        for (ch=‘a‘;ch<=‘z‘;++ch)
        for (j=1;j<=n;++j)
        if (s[j][i]==‘?‘||ch==s[j][i]) g[i][ch-‘a‘]|=1<<j-1;
        f[1][(1<<n)-1]=1; ans=0;
        for (i=1;i<=len;++i)
        for (j=0;j<1<<n;++j)
        if (f[i][j]) for (ch=‘a‘;ch<=‘z‘;++ch)
        f[i+1][j&g[i][ch-‘a‘]]=(f[i+1][j&g[i][ch-‘a‘]]+f[i][j])%mod;
        for (i=0;i<1<<n;++i)
        if (count(i)==k) ans=(ans+f[len+1][i])%mod;
        printf("%d\n",ans);
    }
    return 0;
}

T3

这就是传说中的神题么

暴力的想法都是有的,但是就是刚不出来(只有YZC dalao拿了2分)

标算是DP+KMP+矩阵乘法(快速幂),还是不可食用的

想要标算的同学看BZOJ1009黄学长题解

原文地址:https://www.cnblogs.com/cjjsb/p/9007644.html

时间: 2024-07-31 04:26:24

EZ 2018 05 06 NOIP2018 慈溪中学集训队互测(五)的相关文章

EZ 2018 05 13 NOIP2018 模拟赛(十三)

这次的比赛真心水,考时估分240,然后各种悠闲乱逛 然后测完T1数组开小了炸成40,T2,T3都没开long long,T2炸成20,T3爆0 掉回1600+的深渊,但是还有CJJ dalao比我更惨 T1 这道题就比较simple了,很显然用数据结构乱优化 貌似有很多种解法:单调队列,堆,线段树等等 我主要就讲一下我考试的时候YY出来的线段树 首先我们发现一个性质:对于n次操作之后,序列就进入循环 然后我们只需要处理处前n次询问就可以O(n)处理了 我们开一个前缀和记录原串中1的个数,然后设一

UOJ#191. 【集训队互测2016】Unknown

题意:维护一个数列,每个元素是个二维向量,每次可以在后面加一个元素或者删除一个元素.给定P(x,y),询问对于[l,r]区间内的元素$S_i$,$S_i \times P$的最大值是多少. 首先简单地推出类似斜率优化的式子,那么我们需要在凸包上二分. 学习了一下这份代码http://uoj.ac/submission/69959 使用线段树按下标维护凸包.那么这里有一个问题,如果按照传统的写法,合并一次的复杂度是与$O(区间长度)$的,这样会导致单次插入/删除的时间复杂度变为$O(n)$,是不能

集训队互测2016Unknown(UOJ191)

题目链接 前面部分和lzz的题解是一样的. 首先将输入点(x,y)变为(-y,x)然后,只需找一个向量与(-y,x)的点积最大,即找一个向量在(-y,x)上的投影最长.此时所有的点都是在x轴上方的,容易发现答案一定是在凸包上的,再继续观察,如果有一个点在凸包而不在上凸包上,那么它的右上角及左上角一定有一个点,因此这个点一定不是最优的,所以答案一定在上凸包上,且可以在上凸包上二分. 对于subtask5,使用线段树,每个节点存储这个区间的凸包,合并凸包的话可以将两个凸包上的点归并后线性做凸包. 从

[JZOJ3302] 【集训队互测2013】供电网络

题目 题目大意 给你一个有向图,每个点开始有一定的水量(可能为负数),可以通过边流到其它点. 每条边的流量是有上下界的. 每个点的水量可以增加或减少(从外界补充或泄出到外界),但是需要费用,和增加(减少)流量呈正比例函数关系. 每条边的流量也需要费用,费用和流量呈二次函数关系(常数项为\(0\)). 问将所有水流完的最小花费. 思考历程 这显然是一道上下界最小费用可行流嘛! ==有源有汇的上下界可行流的做法:建立超级源\(ss\)和超级汇\(tt\)(和\(S\).\(T\)),对于\(u\)到

jzoj 2867. 【集训队互测 2012】Contra

Description 偶然间,chnlich 发现了他小时候玩过的一个游戏"魂斗罗",于是决定怀旧.但是这是一个奇怪的魂斗罗 MOD. 有 N 个关卡,初始有 Q 条命. 每通过一个关卡,会得到 u 分和1条命,生命上限为 Q.其中 u=min(最近一次连续通过的关数,R). 若没有通过这个关卡,将会失去1条命,并进入下一个关卡. 当没有生命或没有未挑战过的关卡时,游戏结束,得到的分数为每关得到的分数的总和. 由于 chnlich 好久不玩这个游戏了,每条命通过每个关卡的概率均为p(

[JZOJ2866] 【集训队互测 2012】Bomb

题目 题目大意 给你一个有\(n\)个点的平面. 选择三个点,求两两之间曼哈顿距离和的最大值和最小值. 思考历程&正解 比赛的时候没有想太多,但感觉似乎比较水-- 首先有个很显然的性质,答案为这三个点的最大最小横坐标之差和最大最小纵坐标之差的和. 可以把它看成矩形的周长,容易发现矩形至少一个顶点是三个点之一. 后来才发现水的是求最大值,而不是求最小值. 比赛之后开始和WMY刚-- 最大值是很好求的.我一开始打了个线段树来求,后来发现根本不用-- 求出所有点的\(Xmin,Xmax,Ymin,Ym

jzoj 2866. 【集训队互测 2012】Bomb

Description 给你\(n\)个点,坐标分别为\((xi,yi)\).从中取出三个点,使得其两两间曼哈顿距离和最大和最小,求最大值和最小值. 对于 100% 的数据, N<=100000 , 0<=Xi,Yi<=10^8 Solution 看完题目后感觉要分类讨论,思考1h后果断暴力O(n^3). 但是判断了一下n<=500才跑暴力,得了30分.(?10^9过4s?不判50分) 其实可以O(n^2)暴力的.(听说O(n^2)+优化 = 100) 对于第一个最大值,我们可以\

【uoj#94】【集训队互测2015】胡策的统计(集合幂级数)

题目传送门:http://uoj.ac/problem/94 这是一道集合幂级数的入门题目.我们先考虑求出每个点集的连通生成子图个数,记为$g_S$,再记$h_S$为点集$S$的生成子图个数,容易发现,$h_S=2^{size_S}$,其中$size_S$为点集$S$的极大生成子图内的边数.特殊的,$f_{\o}=g_{\o}=0$. 定义集合幂级数的乘法为子集卷积,考虑集合幂级数$h$和$g$的关系,我们可以得到 $$h=1+\sum_{k \geq 1}\frac{g^k}{k!}=1+e^

[集训队互测2012]calc——DP

题面 Bzoj2655 解析 可以强制让$a$数列递增,最后乘以$n!$ 有一个显然的$dp$,$f[i][j]$表示填前$i$个位置,且填的数最大不超过$j$的序列权值和,易有:$f[i][j] = f[i][j-1] + f[i-1][j-1] * j$ $O(AN)$的$dp$显然会$T$ 设$f[i][j]$是关于$j$的$g(i)$次多项式,$g(0)=0$ 注意到$f[i][j] - f[i][j-1]$就是关于$j$的$g(i)-1$次多项式,将$dp$方程移项:$f[i][j]