洛谷 P2783 有机化学之神偶尔会做作弊 解题报告

P2783 有机化学之神偶尔会做作弊

题目背景

XS中学化学竞赛组教练是一个酷爱炉石的人。

有一天他一边搓炉石一边监考,而你作为一个信息竞赛的大神也来凑热闹。

然而你的化竞基友却向你求助了。

“第1354题怎么做”<--手语 他问道。

题目描述

你翻到那一题:给定一个烃,只含有单键(给初中生的一个理解性解释:就是一堆碳用横线连起来,横线都是单条的)。

然后炎魔之王拉格纳罗斯用他的火焰净化了一切环(???)。所有的环状碳都变成了一个碳。如图所示。

1394419-20180609102222901-1013104284.png

然后指定多组碳,求出它们之间总共有多少碳。如图所示(和上图没有关系)。

1394419-20180609102250413-360424873.png

但是因为在考试,所以你只能把这个答案用手语告诉你的基友。你决定用二进制来表示最后的答案。如图所示(不要在意,和题目没有什么没关系)。

1394419-20180609102309556-151366767.png

输入输出格式

输入格式:

第一行两个整数\(n,m\).表示有\(n\)个点,\(m\)根键

接下来\(m\)行每行两个整数\(u\)\(v\)表示\(u\)号碳和\(v\)号碳有一根键

接下来一个整数\(tot\)表示询问次数

接下来\(tot\)行每行两个整数,\(a,b\)表示询问的两个碳的编号

输出格式:

\(tot\)

每行一个二进制数

说明

1<n<=10000,1<m<=50000

(两个碳不成环)


人生中第一道A掉的黑题!2018.6.9

其实这题思想上不难,简化一下问题即是:对于一个无向图,先把环给缩点缩掉,然后求\(LCA\)即可。

无向图缩点
LCA


code:

#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int N=10010;
const int M=50010;
struct Edge
{
    int to,next;
}edge[M<<1],edge1[M<<1];
vector <int > g[N];
int head[N],cnt=0,n,m,head1[N],cnt1=0;
void add(int u,int v)
{
    edge[++cnt].next=head[u];edge[cnt].to=v;head[u]=cnt;
}
void add1(int u,int v)
{
    edge1[++cnt1].next=head1[u];edge1[cnt1].to=v;head1[u]=cnt1;
}
int time=0,dfn[N],low[N],used[N],ha[N],f[N],s[N],ans[N],dis[N],tot=0,n0=0;
void push(int x){s[++tot]=x;}
void pop(){tot--;}
void tarjan(int now,int fa)
{
    dfn[now]=low[now]=++time;
    push(now);
    used[now]=1;
    for(int i=head[now];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v!=fa)
        {
            if(!dfn[v])
            {
                tarjan(v,now);
                low[now]=min(low[now],low[v]);
            }
            else if(used[v])
                low[now]=min(low[now],dfn[v]);
        }
    }
    if(low[now]==dfn[now])
    {
        n0++;
        int k;
        do
        {
            k=s[tot];
            ha[k]=n0;
            used[k]=0;
            pop();
        }while(k!=now);
    }
}
int find(int x)
{
    return f[x]=f[x]==x?x:find(f[x]);
}
void merge(int x,int y)
{
    f[find(y)]=find(x);
}
void LCA(int now)//求解lca
{
    used[now]=1;
    for(int i=0;i<g[now].size();i++)
    {
        int v=g[now][i];
        if(!used[v])
        {
            LCA(v);
            merge(now,v);
        }
    }
    for(int i=head1[now];i;i=edge1[i].next)
    {
        int v=edge1[i].to;
        if(used[v])
        {
            int anc=find(v);
            ans[i+1>>1]=dis[v]+dis[now]-(dis[anc]<<1)+1;
        }
    }
}
void out(int x)
{
    int len=0,tt[20];
    while(x)
    {
        tt[++len]=x&1;
        x>>=1;
    }
    for(int i=len;i;i--)
        printf("%d",tt[i]);
    printf("\n");
}
void dfs0(int now,int dep)
{
    used[now]=1;
    dis[now]=dep;
    for(int i=0;i<g[now].size();i++)
    {
        int v=g[now][i];
        if(!used[v]) dfs0(v,dep+1);
    }
}
void init()
{
    for(int i=1;i<=n0;i++) f[i]=i;
    for(int i=1;i<=n0;i++)
        if(!used[i])
            dfs0(i,1);
}
int main()
{
    scanf("%d%d",&n,&m);
    int u,v,q;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i,0);
    for(int i=1;i<=n;i++)
        for(int j=head[i];j;j=edge[j].next)
        {
            int v=edge[j].to;
            if(ha[v]!=ha[i])
                g[ha[i]].push_back(ha[v]);
        }
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        scanf("%d%d",&u,&v);
        add1(ha[u],ha[v]);
        add1(ha[v],ha[u]);
    }
    init();
    memset(used,0,sizeof(used));
    for(int i=1;i<=n0;i++)
        if(!used[i])
            LCA(i);
    for(int i=1;i<=q;i++)
        out(ans[i]);
    return 0;
}

2018.6.9

转载于:https://www.cnblogs.com/butterflydew/p/9158742.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 防止作弊的API主要分为两种类型,一种是基于硬件的防作弊API,另一种是基于软件的防作弊API。 基于硬件的防作弊API主要包括: 1. 时钟校准API:可以检测到CPU时钟的变化,防止玩家通过修改时钟来作弊。 2. 唯一设备标识符API:可以生成唯一的设备标识符,防止玩家使用多个账号或者设备进行作弊。 3. 加密API:可以对游戏的数据进行加密,防止玩家通过篡改游戏数据来作弊。 基于软件的防作弊API主要包括: 1. 内存检测API:可以检测到玩家修改游戏内存的行为,防止玩家通过修改内存来作弊。 2. 程序完整性检测API:可以检测到程序被修改或者篡改的行为,防止玩家通过修改程序来作弊。 3. 行为检测API:可以检测到玩家的不正常行为,例如速度过快、跳跃过高等行为,防止玩家通过改变游戏行为来作弊。 总的来说,防止作弊的API需要综合使用多种技术,包括硬件和软件方面的技术,才能达到最好的效果。 ### 回答2: 防止作弊的API可以使用以下几种方法: 1. 限制请求频率:通过API管理工具,限制每个用户或IP地址的请求频率,防止恶意用户通过快速的请求进行作弊。 2. 用户认证和授权:要求用户使用API时进行身份认证,并通过授权机制限制只有有效用户可以访问API。可以使用OAuth等授权框架实现。 3. 验证码:在敏感操作或需要保护的接口上,引入验证码机制,要求用户输入验证码才能完成请求。这样可以防止自动化脚本或机器人进行作弊。 4. 接口加密和数字签名:通过在请求中加入加密或签名参数,确保请求的完整性和安全性,防止中间人攻击或篡改请求数据。 5. IP地址过滤和黑名单:通过对IP地址进行过滤和黑名单设置,屏蔽已知的恶意IP地址,减少恶意访问和作弊行为。 6. 使用机器学习算法检测异常行为:通过收集和分析API访问数据,使用机器学习算法识别异常行为,如频繁切换IP,大量请求错误信息等,及时发现可能的作弊行为。 7. API访问日志和监控:记录和监控所有API的访问日志,及时发现异常请求和异常行为,进行及时相应和调整。 需要根据实际应用场景和需求选择合适的防作弊措施,组合使用上述API可以最大限度地提高防作弊效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值