牛客练习赛11 B trie树+拓扑判环 E 分治求平面最近点对

牛客练习赛11

假的字符串
题意:给定n个字符串,互不相等,你可以任意指定字符之间的大小关系(即重定义字典序),求有多少个串可能成为字典序最小的串,并输出它们。

tags:好题

对于一个字符串,

1】如有其它字符串是它的前缀,那肯定不可能。这个直接用字典树处理就可以。

2】但如果以这个字符串为最小,怎么判定其它字符串不会矛盾呢?

其实矛盾的情况详细一点说是: 比如要以  abcd 为最小, 但又有另一个字符串 aba ,这就矛盾了。

对这种情况,在跑字典树的时候,我们对有相同父亲结点的多个儿子结点相互连边,然后每次拓扑排序判一下环即可。

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 30005, M = 300005;

int n, cnt, tr[M][26], val[M*26];
string s[N];
void Insert(int ci)
{
    int len=s[ci].size(), now=0;
    rep(j,0,len-1)
    {
        int tmp=s[ci][j]-‘a‘;
        if(tr[now][tmp]==0) tr[now][tmp]=++cnt;
        now = tr[now][tmp];
    }
    ++val[now];
}
vector< int > G[26];
int in[26];
queue< int > q;
bool Toposort()
{
    rep(i,0,25) if(in[i]==0) q.push(i);
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        for(int i=0; i<G[u].size(); ++i)
        {
            --in[G[u][i]];
            if(in[G[u][i]]==0) q.push(G[u][i]);
        }
    }
    rep(i,0,25) if(in[i]) return false;
    return true;
}
bool check(int ci)
{
    rep(i,0,25) G[i].clear(), in[i]=0;
    int len=s[ci].size(), now=0;
    rep(j,0,len-1)
    {
        int tmp=s[ci][j]-‘a‘;
        if(j<len-1 && val[tr[now][tmp]]) return false;
        rep(i,0,25) {
            if(tr[now][i] && i!=tmp)
                G[tmp].PB(i), ++in[i];
        }
        now = tr[now][tmp];
    }
    if(Toposort()) return true;
    return false;
}
int ans[N], ans1;
int main()
{
    scanf("%d", &n);
    rep(i,1,n)
    {
        cin>> s[i];
        Insert(i);
    }
    rep(i,1,n)
    {
        if(check(i)) ans[++ans1]=i;
    }
    printf("%d\n", ans1);
    rep(i,1,ans1)
        cout<<s[ans[i]]<<endl;

    return 0;
}

求最值

题意:

给你一个长为n的序列a

定义f(i,j)=(i-j)2+g(i,j)2

g是这样的一个函数

求最小的f(i,j)的值,i!=j

tags:翻译一下,就是  (i-j)^2+(sum[i]-sum[j])^2  最小, 也就是最近点对。 分治 O(nlogn)

模板:

// 分治求平面最近点对
struct Point { double x, y; };
struct Point point[N], *px[N], *py[N];
double get_dis(Point *p1,Point *p2) {
    return sqrt((p1->x-p2->x)*(p1->x-p2->x)+(p1->y-p2->y)*(p1->y-p2->y));
}
bool cmpx(Point *p1,Point *p2) { return p1->x<p2->x; }
bool cmpy(Point *p1,Point *p2) { return p1->y<p2->y; }
double min(double a,double b) { return a<b?a:b; }
double closest(int s,int e)
{
    if(s+1==e)
        return get_dis(px[s],px[e]);
    if(s+2==e)
        return min(get_dis(px[s],px[s+1]),min(get_dis(px[s+1],px[e]),get_dis(px[s],px[e])));
    int mid=(s+e)>>1;
    double ans=min(closest(s,mid),closest(mid+1,e));//递归求解
    int i, j, cnt=0;
    for(i=s; i<=e; i++)//把x坐标在px[mid].x-ans~px[mid].x+ans范围内的点取出来
    {
        if(px[i]->x>=px[mid]->x-ans && px[i]->x<=px[mid]->x+ans)
            py[cnt++]=px[i];
    }
    sort(py, py+cnt, cmpy);//按y坐标排序
    for(i=0; i<cnt; i++)
    {
        for(j=i+1;j<cnt;j++)//py数组中的点是按照y坐标升序的
        {
            if(py[j]->y-py[i]->y>=ans)  break;
            ans=min(ans,get_dis(py[i],py[j]));
        }
    }
    return ans;
}
/*void Init()
{
    for(int i=1; i<=n; ++i) {
        scanf("%lf%lf", &point[i].x, &point[i].y);
        px[i] = &point[i];
    }
    sort(px+1, px+1+n, cmpx);
}*/

// E
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 100005;

struct Point { double x, y; };
struct Point point[N], *px[N], *py[N];
double get_dis(Point *p1,Point *p2) {
    return sqrt((p1->x-p2->x)*(p1->x-p2->x)+(p1->y-p2->y)*(p1->y-p2->y));
}
bool cmpx(Point *p1,Point *p2) { return p1->x<p2->x; }
bool cmpy(Point *p1,Point *p2) { return p1->y<p2->y; }
double min(double a,double b) { return a<b?a:b; }
double closest(int s,int e)
{
    if(s+1==e)
        return get_dis(px[s],px[e]);
    if(s+2==e)
        return min(get_dis(px[s],px[s+1]),min(get_dis(px[s+1],px[e]),get_dis(px[s],px[e])));
    int mid=(s+e)>>1;
    double ans=min(closest(s,mid),closest(mid+1,e));//递归求解
    int i, j, cnt=0;
    for(i=s; i<=e; i++)//把x坐标在px[mid].x-ans~px[mid].x+ans范围内的点取出来
    {
        if(px[i]->x>=px[mid]->x-ans && px[i]->x<=px[mid]->x+ans)
            py[cnt++]=px[i];
    }
    sort(py, py+cnt, cmpy);//按y坐标排序
    for(i=0; i<cnt; i++)
    {
        for(j=i+1;j<cnt;j++)//py数组中的点是按照y坐标升序的
        {
            if(py[j]->y-py[i]->y>=ans)  break;
            ans=min(ans,get_dis(py[i],py[j]));
        }
    }
    return ans;
}
/*void Init()
{
    for(int i=1; i<=n; ++i) {
        scanf("%lf%lf", &point[i].x, &point[i].y);
        px[i] = &point[i];
    }
    sort(px+1, px+1+n);
}*/

int n;
double ai, sum[N];
int main()
{
    scanf("%d", &n);
    rep(i,1,n)
    {
        scanf("%lf", &ai);
        sum[i]=sum[i-1]+ai;
        point[i].x=1.0*i, point[i].y=sum[i];
        px[i] = &point[i];
    }
    sort(px+1, px+1+n, cmpx);
    double ans = closest(1, n);
    printf("%.0f\n", ans*ans);

    return 0;
}

原文地址:https://www.cnblogs.com/sbfhy/p/8428890.html

时间: 2024-11-08 21:47:26

牛客练习赛11 B trie树+拓扑判环 E 分治求平面最近点对的相关文章

牛客练习赛18

链接:https://www.nowcoder.com/acm/contest/110/A来源:牛客网 最大乘积 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言524288K 64bit IO Format: %lld 题目描述 这题要你回答T个询问,给你一个正整数S,若有若干个正整数的和为S,则这若干的数的乘积最大是多少?请输出答案除以2000000000000000003(共有17 个零) 的余数. 举例来说,当 S = 5 时,若干个数的和为 5

转载:牛客练习赛17 c 规律题

转载:https://www.cnblogs.com/zzqc/p/8995135.html C.链接:https://www.nowcoder.com/acm/contest/109/C来源:牛客网 题目描述 给定长度为n的数组a,定义一次操作为:1. 算出长度为n的数组s,使得si= (a[1] + a[2] + ... + a[i]) mod 1,000,000,007:2. 执行a = s:现在问k次操作以后a长什么样. 输入描述: 第一行两个整数n,k(1 <= n <= 2000,

hdu 4324 Triangle LOVE(拓扑判环)

Triangle LOVE Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 3603    Accepted Submission(s): 1416 Problem Description Recently, scientists find that there is love between any of two people. Fo

SDNU 1089.拓扑排序(拓扑判环小顶堆)

Description 给定一个有向图,若图无环,则将其进行拓扑排序并输出,否则输出IMPOSABLE. Input 第一行为两个整数n(1<=n<=1000).m(1<=m<=100000): 之后m行,每行两个整数a.b(0 < a, b <= n)表示一条从a到b的有向边. Output 若存在环,输出IMPOSABLE,否则输出一行用一个空格隔开的拓扑排序的结果,若存在多个结果,输出字典序最小的. Sample Input 5 4 1 2 2 3 3 4 4 5

牛客练习赛7 E 珂朵莉的数列(树状数组+爆long long解决方法)

https://www.nowcoder.com/acm/contest/38/E 题意: 思路: 树状数组维护.从大佬那里学习了如何处理爆long long的方法. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 typedef long long ll; 7 const int maxn =

牛客练习赛1 补题记录

A 矩阵 中文题意,要找一个最大的k阶子矩阵在原矩阵中出现过两次. 需要将这个矩阵进行Hash,也就是需要二维Hash,先把每一行Hash了,再把每一列Hash了,有一点前缀的感觉. 预处理完Hash值之后,二分答案k,check过程是在$O(n ^ 2)$枚举起点,这里其实枚举终点方便一些,边界比较好处理,把每个k阶矩阵的hash值存下来,最后看有没有两个一样的. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int

牛客练习赛 16

在各位ak的大佬中,我感觉我寄几好菜啊... 题目描述 给定字符串s,s只包含小写字母,请求出字典序最大的子序列. 子序列:https://en.wikipedia.org/wiki/Subsequence 字典序:https://en.wikipedia.org/wiki/Lexicographical_order 输入描述: 一行一个字符串s (1 <= |s| <= 100,000). 输出描述: 字典序最大的子序列. 示例1 输入 ababba 输出 bbba 示例2 输入 abbcb

牛客练习赛16

A   字典序最大的子序列 > 25960019 一开始潜意识看成了循环,最长子串-- 找每个字母最晚出现的位置,那么比它小的字符必须出现在 在它之后的位置 1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <cmath> 5 #include <set> 6 #include <map> 7 #include <list>

牛客练习赛7E 珂朵莉的数列

题意:求所有子区间的逆序数对数之和 题解:线段树维护,对于每一对逆序数(l,r)属于l*(n-r+1)个区间,计算每一对对结果的贡献即可,可用树状数组维护,sum维护(n-r+1),按逆序数那样操作 这题最狗的地方是爆longlong,java又超时...,用了一个小技巧,避免爆longlong #include<bits/stdc++.h> #define fi first #define se second #define ll long long #define ull unsigned