码迷,mamicode.com
首页 > 其他好文 > 详细

2020 2.5

时间:2020-02-06 22:49:23      阅读:71      评论:0      收藏:0      [点我收藏+]

标签:需要   min   src   out   har   处理   两种   编号   第一个   

t1

初始有k个装备,每个装备n种属性,现在有q个操作(合成的装备编号为现在编号最大的装备编号+1,原装备不消失)

1 x y 将第x个和第y个装备每项属性取max合成一个新装备

2 x y 将第x,y个每项取min。

3 x y 询问第x个装备的第y项属性值。

n,q<=1e5 k<=12

题解

定义b[i][j]=1,j是一个状态,表示第i个装备可以对第j个状态中的所有装备的最小值,取max。

初始b[i]中所有包含(1<<i-1)的状态都为1。

先将每种属性里的装备从大到小排序。

1操作就将两个的b取|,表示可以这两种装备的所有可取状态都可以取。

2操作就是对两个的b取&,表示取最小值。

3操作,顺序枚举该属性的所有初始装备依次累加状态,第一个可以取得装备即为答案。

代码如下:

技术图片
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,k,q;
struct pigu
{
    int id,val;
}a[N][15];
bitset <5000> bi[N+20];//bi[i][j]=1表示可以取j状态的最小值 
inline int read()
{
    char c=getchar();
    int x=0,f=1;
    while(!isdigit(c)) {if(c==-) f=-1;c=getchar();}
    while(isdigit(c)) {x=(x<<3)+(x<<1)+c-0;c=getchar();}
    return x*f;
}
inline bool cmp(pigu x,pigu y)
{
    return x.val>y.val;
}
int main()
{
    freopen("compose1.in","r",stdin);
    freopen("compose.out","w",stdout);
    n=read();k=read();q=read();
    for(int i=1;i<=k;i++) bi[i].reset(); 
    for(int i=1;i<1<<k;i++)
        for(int j=1;j<=k;j++)
            if(i&(1<<j-1))
                bi[j][i]=1;
    for(int i=1;i<=k;i++)
        for(int j=1;j<=n;j++)
        {
            a[j][i].val=read();
            a[j][i].id=i;
        }
    for(int i=1;i<=n;i++) sort(a[i]+1,a[i]+k+1,cmp);
    int tot=k;
    for(int i=1,x,y,z;i<=q;i++)
    {
        x=read();y=read();z=read();
        if(x==1)
        {
            tot++;
            bi[tot]=bi[y]|bi[z];
        }
        if(x==2)
        {
            tot++;
            bi[tot]=bi[z]&bi[y];
        }
        if(x==3)
        {
            int now=0,ans=0;
            for(int j=1;j<=k;j++)
            {
                now|=(1<<a[z][j].id-1);
                ans=max(ans,a[z][j].val*bi[y][now]);
            }
            cout<<ans<<"\n";
        }
    }
}
View Code

t2

给出n*n 01矩阵A和n维向量b,每次读入x询问 A^{x} *b

50分做法。

先预处理出2^{n} 的矩阵乘积,查询时就只需要向量乘矩阵,每次只需要n方即可。

复杂度预处理n^{3} log_2{k}+q*n*n*log_2{k}。

100分做法。

好像可以用bitset优化再翻转矩阵行列,还要先判断每一位是否为1在乘行列。

不知道能不能过

莫得代码

t3

最后答案显然就是 \sum 全部变为某种颜色的期望步数乘以变为该种颜色的概率,设p[i]表示现在有i个这样的颜色到得手的概率,f[i]为现在有i个的期望步数。

技术图片

 

技术图片

 

 

 技术图片

 

知道了g[n]和g[0],如果知道了g[1]就舒服了,

 然后就求g[1],然后反手就被发现了一个性质

技术图片

 

 然后线性递推即可。

代码如下:

技术图片
#include <algorithm>
#include <cstdio>

typedef long long ll;

inline int read(){
    char c=getchar(); int x=0,ft=1;
    for(;c<0||c>9;c=getchar()) if(c==-) ft=-1;
    for(;c>=0&&c<=9;c=getchar()) x=x*10+c-0;
    return x*ft;
}

const int mod=1e9+7;

inline int fpow(int x,int k){
    int res=1;
    for(;k;k>>=1,x=(ll)x*x%mod) if(k&1) res=(ll)res*x%mod;
    return res;
}

const int N=1e5+5;

int n,a[2005],sum,lim,f[N],ans;

int main(){
    freopen("hard.in","r",stdin);
    freopen("hard.out","w",stdout);
    n=read();
    for(int i=1;i<=n;++i){
        lim=std::max(lim,a[i]=read()); sum=(sum+a[i])%mod; 
    }
    f[1]=(ll)(sum-1)*(sum-1)%mod*fpow(sum,mod-2)%mod;
    for(int i=1;i<lim;++i){
        int g=(ll)(sum-1)*fpow(sum-i,mod-2)%mod;
        f[i+1]=(((ll)2*f[i]-f[i-1]-g)%mod+mod)%mod;
    }
    for(int i=1;i<=n;++i) ans=(ans+f[a[i]])%mod;
    printf("%d\n",ans);
    fclose(stdin); fclose(stdout); return 0;
}
/*
4
2 1 5 7
*/
View Code

 

2020 2.5

标签:需要   min   src   out   har   处理   两种   编号   第一个   

原文地址:https://www.cnblogs.com/betablewaloot/p/12271236.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!