2014 多校赛 第一场

题目链接

A - Couple doubi

题意:桌上共有 k 个球,第i个球的值为 (1^i+2^i+...+(p-1)^i )mod p
DouBiXp 和 他的女朋友 DouBiNan 轮流拿球,DouBiNan先拿,
所有的球都拿完后,谁手上球的值总和更大谁就赢,
已知 k,p,且p为素数,
若DouBiNan赢输出"YES",否则输出"NO"

分析:DouBiNan先拿,为了赢肯定先拿没有被拿的球中值最大的,
找规律得 每个球的值要么为 0,要么为某个的正数x,且每p-1个球有一个的值为x
那么如果值为x的球个数如果为奇数,则DouBiNan赢,否则赢不了

#include<stdio.h>
int main()
{
    int p,n;
    while(scanf("%d%d",&n,&p)!=EOF){
        if((n/(p-1))%2)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}


D - Task
题意:有n台机器和m个任务,第i个任务需要xi时间去完成,且它的难度等级为yi
若第i个任务被完成,可获得收益 500*xi+2*yi
每台机器有一个最大工作时间和能完成的最大难度等级,
若某台机器要完成某任务,则机器的工作时间要不低于任务需要的时间,
机器的难度等级不低于任务的难度等级,
一台机器一天只能完成一次任务,且一个任务只能由一台机器完成

已知每台机器和每个任务的完成时间和难度等级,
求一天能完成的最多的任务数,在此前提下的最大收益

分析:贪心求解
收益只有完成的任务的x,y有关,且x,y越大,获得的收益越大
所以要优先完成x更大的任务,若x相等,要优先完成y大的任务
即任务要按x从大到小排序,若x相等则按y从大到小排序
任务的x按从大到小排序,再给任务匹配机器

当有多台机器符合x条件,那么要选择y满足条件的最小的y,
这样没被用的更大的y的机器,更可能符合完成其他任务

#include<stdio.h>
#include<algorithm>
#define N 100000
using namespace std;
struct stu{
    int time,level;
}task[N+10],machine[N+10];
int cmp(stu a,stu b){
    if(a.time==b.time)
        return a.level>b.level;
    return a.time>b.time;
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        for(int i=1;i<=n;i++)
            scanf("%d%d",&machine[i].time,&machine[i].level);
        for(int i=1;i<=m;i++)
            scanf("%d%d",&task[i].time,&task[i].level);
        sort(machine+1,machine+1+n,cmp);
        sort(task+1,task+1+m,cmp);
        int j=1,cnt[105]={0},maxm=0;
        long long ans=0;
        for(int i=1;i<=m;i++){
            while(j<=n&&task[i].time<=machine[j].time){
                cnt[machine[j].level]++;
                j++;
            }
            for(int k=task[i].level;k<=100;k++){
                if(cnt[k]){
                    maxm++;
                    ans+=task[i].time*500+task[i].level*2;
                    cnt[k]--;
                    break;
                }
            }
        }
        printf("%d %I64d\n",maxm,ans);
    }
    return 0;
}


E - Peter's Hobby

题意:已知昨天天气与今天天气状况的概率关系(wePro),和今天天气状态和叶子湿度的概率关系(lePro)
第一天为sunny 概率为 0.63,cloudy 概率 0.17,rainny 概率 0.2.
给定n天的叶子湿度状态,求这n天最可能的天气情况

分析:概率dp
设 dp[i][j] 表示第i天天气为j的最大概率,
pre[i][j]表示第i天天气最可能为j的前一天天气,
dp[i][j]=max(dp[i-1][k]+log(wePro[k][j])+log(lePro[j][lePos[i]])) (k=0,1,2 表示昨天的天气)

注:由于概率越乘越小,考虑精度原因,用log取对数
log(a*b*c) = log a + log b +log c

#include<stdio.h>
#include<string.h>
#include<math.h>
char Con[5][10]={"Dry","Dryish","Damp","Soggy"};
char We[5][10]={"Sunny","Cloudy","Rainy"};
double lePro[3][4]={0.6,0.2,0.15,0.05,
                  0.25,0.3,0.2,0.25,
                  0.05,0.10,0.35,0.50};  //叶子
double wePro[3][3]={0.5,0.375,0.125,
                    0.25,0.125,0.625,
                    0.25,0.375,0.375};   //天气
double init[3]={0.63,0.17,0.2};
double dp[55][3],pre[55][3];
int n,lePos[55];
void solve()
{
    for(int i=0;i<3;i++)
        dp[1][i]=log(init[i])+log(lePro[i][lePos[1]]);
    for(int i=2;i<=n;i++){
        for(int j=0;j<3;j++){  //今天天气
            double maxp=-1e8;
            int pos=0;
            for(int k=0;k<3;k++){  //昨天天气
                double temp=dp[i-1][k]+log(wePro[k][j])+log(lePro[j][lePos[i]]);
                if(temp>maxp){
                    maxp=temp;
                    pos=k;
                }
            }
            dp[i][j]=maxp;
            pre[i][j]=pos;
        }
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    for(int k=1;k<=T;k++){
        printf("Case #%d:\n",k);
        scanf("%d",&n);
        char con[10];
        for(int i=1;i<=n;i++){
            scanf("%s",con);
            for(int j=0;j<4;j++)
                if(strcmp(con,Con[j])==0){
                    lePos[i]=j;
                    break;
                }
        }
        solve();
        double maxp=-1e8;
        int ans[55];
        for(int i=0;i<3;i++)
        if(dp[n][i]>maxp){
            maxp=dp[n][i];
            ans[n]=i;
        }
        for(int i=n-1;i>=1;i--)
            ans[i]=pre[i+1][ans[i+1]];
        for(int i=1;i<=n;i++)
            printf("%s\n",We[ans[i]]);
    }
    return 0;
}

资料扩展:详情点此
本题属于 隐马尔可夫模型
马尔可夫模型:统计模型,每个状态只依赖于之前的状态

马尔可夫模型可用马尔可夫过程描述
我们就为上面的一阶马尔科夫过程定义了以下三个部分:
  状态:晴天、阴天和下雨
  初始向量:定义系统在时间为0的时候的状态的概率
  状态转移矩阵:每种天气转换的概率
  所有的能被这样描述的系统都是一个马尔科夫过程。

隐马尔可夫模型 (Hidden Markov Model) 是一种统计模型,用来描述一个含有隐含未知参数的马尔可夫过程。
包含隐藏状态 (如:天气状态)和 可观状态(如:叶子的湿度)

可以观察到的状态序列和隐藏的状态序列是概率相关的


I - Turn the pokers

题意:有m张牌,初始状态都是正面朝下,现在要进行n次操作,
第i次操作要翻ai张牌,求n次操作后,牌的状态可能有多少种?


分析:牌只有两种状态,设面朝下为0,面朝上为1,则初始状态都为0
很显然每一张牌的状态只跟这张牌被翻的次数的奇偶性有关。
翻牌i次后1的个数的奇偶性一定与前i次翻牌的总张数 a1+a2+...+ai的奇偶性相同
(初始状态1的个数为0,是偶数,1.若翻偶数张牌,1的个数还是偶数
2.若翻奇数张,得到的还是奇数,
在第2种情况下若再翻奇数次,可能会翻奇数个0,偶数个1,或者偶数个0,奇数个1,
结果还是奇数,而两次翻牌张数和为偶加奇,也是奇数。。。可自行证明)

若终态有最少有min个1,最多有max个1,那么1的个数可能为 min,min+2,min+4,...,max
即牌的状态可能有 C(m,min)+C(m,min+2)+C(m,min+4)+...+C(m,max)
这样就转化为求min,max及组合数了
C(m,i)=m!/(i!*(m-i)!),因为最终要取余,而阶乘数太大存不了,还涉及到除法,
直接取余再除肯定不行(同余定理不适用于除法)
可以利用费马小定理解决:
由定理得:a^(p-1)≡1%p
则 a^(p-2)≡1/a%p
因为p很大,需要用快速幂取余来做

#include<stdio.h>
#define N 100000
#define mod 1000000009
#define LL long long
LL fact[N+10];
void init()
{
    fact[0]=1;
    for(int i=1;i<=N;i++)
        fact[i]=fact[i-1]*i%mod;
}
LL powMod(LL a,LL b)
{
    LL ans=1;
    a%=mod;
    while(b){
        if(b%2)
            ans=ans*a%mod;
        b/=2;
        a=a*a%mod;
    }
    return ans;
}
int main()
{
    int n,m;
    init();
    while(scanf("%d%d",&n,&m)!=EOF){ //m张扑克,n次操作
        int min1,max1,tempMin=0,tempMax=0; //1的最小最大个数
        while(n--){
            int x;
            scanf("%d",&x);
            //计算最少的1,要尽可能让1->0
            if(x<=tempMin)
                min1=tempMin-x;
            else if(x<=tempMax){
                if((x%2)==(tempMin%2))
                    min1=0;
                else
                    min1=1;
            }
            else
                min1=x-tempMax;
            //计算最多的1,要尽可能让0->1
            if(x<=m-tempMax)
                max1=tempMax+x;
            else if(x<=m-tempMin){
                if((x%2)==((m-tempMin)%2))
                    max1=m;
                else
                    max1=m-1;
            }
            else
                max1=m-(x-(m-tempMin));
            tempMin=min1;
            tempMax=max1;
        }
        LL ans=0;
        for(int i=min1;i<=max1;i+=2) //费马小定理
            ans=(ans+(fact[m]*powMod(fact[i]*fact[m-i],mod-2))%mod)%mod;
        printf("%I64d\n",ans);
    }
    return 0;
}



G - Xor
题意:有n个数 (a0,a1,..,an),
f(x)= 满足 b1 xor b2 xor ... xor bn = x 的个数 (0<=bi<=ai)
要进行m次操作
Q x, 求 f(x)
C x y,将第x个数 即 ax 修改为 y

分析:对于这种多查询多维护的题可以用线段树求解
线段树:
是一种擅长处理区间的数据结构。
对其的查找和维护的时间复杂度都是O(log n).
未优化的空间复杂度为 2n

若a0=100101 (二进制)
则b0 =0***** 或 1000** 或 100100 或 100101  (0<=b0<=a0)
将b中确定的位称为前缀,不确定的位(为0或1)称为后缀
则 线段树中结点需要 包含 前缀的值,后缀位数,及组成该形式的数的个数
前缀最大到 1000 (十进制),后缀 最多为 10 ,可以用一个int存这两个信息
因为 10用 4位二进制就可表示,可以用后4位存后缀位数
组成该形式的数的个数 也可用 一个int即可
而b有多种可能形式,且个数未知
所以线段树的每个结点 可用 vector<pair<int,int> > 存储

子树根结点由左右孩子异或得到,将左右孩子可能的形式的数两两异或
可求子根结点,最终可得根结点(b1 xor b2 xor ... xor bn)每种情况的个数
求f(x) 即求根结点 每种情况能组成与x的相等的值的总和
每种情况是否能组成与x相等的值,即看前缀的值与x的前缀的值是否相等

#include<cstdio>
#include<vector>
#include<map>
#define N 20000
#define mod 1000000007
using namespace std;
int a[N+10],minlen;
vector<pair<int,int> > tree[2*N+10];
vector<pair<int,int> > creat_node(int val)
{
    vector<pair<int,int> >temp;
    for(int i=0;i<10;i++){ //val即a[i]最大1000,最多由10位二进制组成
        if(val&(1<<i)){  //判断val第i位是否为1
            int first=(((val>>i)^1)<<4)|i;  //保留从第i位开始的前缀,并将第i位的1变成0
         //且前缀后面添加4位,用来存后缀的位数,后缀位数最多为10,由四位二进制可表示
            temp.push_back(make_pair(first,1));
            //pair的second元素用来存组成上诉形式的数的个数
        }
    }
    temp.push_back(make_pair(val<<4,1));  //与val相等,则前缀为val,后缀位数为0
    return temp;
}
int Xor(int valL,int valR)
{
    int lenL=valL&0xf,lenR=valR&0xf;
    if(lenL>lenR){
        swap(lenL,lenR);
        swap(valL,valR);
    }
    valL>>=4;
    valR>>=4;
    valL>>=(lenR-lenL);
    minlen=lenL;
    return (valL^valR)<<4|lenR;
}
void pushUp(int node)     //根据左右孩子求根节点
{
    map<int,int> m;
    tree[node].clear();
    int lenL=tree[2*node].size();
    int lenR=tree[2*node+1].size();
    int cnt=0;
    for(int i=0;i<lenL;i++){
        for(int j=0;j<lenR;j++){
            int first=Xor(tree[2*node][i].first,tree[2*node+1][j].first);
            long long numL=tree[node*2][i].second;
            long long numR=tree[node*2+1][j].second;
            int second=numL*numR%mod*(1<<minlen)%mod;
            if(m.find(first)==m.end()){
                m[first]=cnt++;
                tree[node].push_back(make_pair(first,second));
            }
            else{
                int pos=m[first];
                tree[node][pos].second=(tree[node][pos].second+second)%mod;
            }
        }
    }
}
void build(int l,int r,int node)      //建树
{
    if(l==r){
        tree[node]=creat_node(a[l]);
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,node*2);
    build(mid+1,r,node*2+1);
    pushUp(node);
}
void update(int l,int r,int node,int pos,int val)  //更新维护树
{
    if(l==r){
        tree[node]=creat_node(val);
        return;
    }
    int mid=(l+r)>>1;
    if(mid>=pos)
        update(l,mid,node*2,pos,val);
    else
        update(mid+1,r,node*2+1,pos,val);
    pushUp(node);
}
int query(int x,int node)            //查找
{
    int ans=0,num=tree[node].size();
    for(int i=0;i<num;i++){
        int first=tree[node][i].first;
        int len=first&0xf;
        first>>=4;
        if(first==(x>>len))
            ans=(ans+tree[node][i].second)%mod;
    }
    return ans;
}
int main()
{
    int T,n,m;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        build(1,n,1);

        while(m--){
            char ope[3];
            scanf("%s",ope);
            if(ope[0]=='Q'){
                int x;
                scanf("%d",&x);
                int ans=query(x,1);
                printf("%d\n",ans);
            }
            else{
                int x,y;
                scanf("%d%d",&x,&y);
                update(1,n,1,x+1,y);
            }
        }
    }
    return 0;
}


<think>好的,用户想了解孟德尔随机化中效性检验的显著性计算方法。首先,我需要回忆相关知识。孟德尔随机化(MR)利用遗传变异作为工具变量来估计暴露对结局的因果效应。效性检验是为了检测工具变量是否存在水平效性,即遗传变异是否通过其他途径影响结局,而非仅通过暴露因素。 根据提供的引用,特别是引用[2]中提到的敏感性分析,包括异质性检验和水平效性检验。效性检验通常使用MR-Egger回归方法,其截距项的显著性可以评估效性是否存在。MR-Egger的截距项如果显著偏离零,则提示存在效性。 接下来需要详细说明计算步骤。首先,进行MR分析,获取各工具变量的效应值和标准误。然后,应用MR-Egger回归,得到截距项及其标准误,进而计算p值。此外,还可以使用其他方法如加权中位数法或Mendelian随机态性残差和离群值(MR-PRESSO)来检测效性。 需要确保解释清楚每个步骤的意义,比如MR-Egger回归的原理,截距项的作用,以及如何判断显著性。同时要提到相关R包如TwoSampleMR和MR-PRESSO的使用,因为用户可能需要进行实际操作。另外,引用中的例子显示使用mr_heterogeneity函数进行异质性检验,这可能与效性检验有关联,需要区分两者。 用户可能需要了解如何解释结果,例如p值小于0.05时的意义,以及如何处理存在效性的情况,比如剔除离群变异。还要注意确保回答中的LaTeX公式格式正确,如效应值b和标准误se的表示,回归模型中的公式用$$...$$包裹。 最后,生成相关问题时要围绕效性检验的方法、工具变量有效性、处理效性的策略等方面提问,帮助用户进一步学习。</think>### 孟德尔随机化中效性检验的显著性计算 在孟德尔随机化(Mendelian Randomization, MR)中,**效性检验**用于评估工具变量(IVs)是否存在水平效性(即遗传变异通过非暴露途径直接影响结局)。以下是计算效性检验显著性的关键步骤: --- #### 1. **MR-Egger回归法** **原理**:通过回归模型评估工具变量的效性。若回归截距项(intercept)显著偏离0,则提示存在水平效性[^2]。 **模型公式**: $$ \hat{\beta}_{Yj} = \alpha + \beta_{IV}\hat{\beta}_{Xj} + \epsilon_j $$ 其中: - $\hat{\beta}_{Xj}$和$\hat{\beta}_{Yj}$是第$j$个SNP对暴露和结局的效应值 - $\alpha$为截距项,反映平均效性效应 - $\beta_{IV}$为因果效应估计值 **显著性计算**: - 使用**加权回归**(权重为结局效应值的标准误倒数) - 通过**t检验**判断截距项$\alpha$是否显著($p < 0.05$表示存在效性) --- #### 2. **MR-PRESSO方法** **原理**:通过检测离群SNP并修正因果效应估计,识别效性变异[^3]。 **步骤**: 1. 计算所有SNP的原始因果效应 2. 模拟数据集并检测离群值 3. 比较离群值存在与否的模型差异(通过全局检验的$p$值) --- #### 3. **敏感性分析** - **异质性检验**:使用Cochran’s Q检验,若$p < 0.05$提示工具变量存在异质性或效性。 - **加权中位数法**:对效性较稳健,结果与IVW法差异较大时需警惕效性。 --- #### 示例代码(R语言) ```r # 使用TwoSampleMR包进行效性检验 library(TwoSampleMR) dat <- harmonise_data(exposure_dat, outcome_dat) # 数据协调[^1] res_egger <- mr_egger(dat) # MR-Egger回归 pleiotropy_test <- mr_pleiotropy_test(dat) # 直接调用效性检验函数 # 输出截距项p值 pleiotropy_test$pval ``` --- ### 关键结果解读 | 方法 | 显著性判断条件 | 处理建议 | |---------------|--------------------------|------------------------------| | MR-Egger | 截距项$p < 0.05$ | 剔除离群SNP或使用稳健方法 | | MR-PRESSO | 全局检验$p < 0.05$ | 移除离群值后重新分析 | | Cochran’s Q | $Q$统计量$p < 0.05$ | 检查工具变量假设或使用FE-IVW | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值