zoukankan      html  css  js  c++  java
  • 省选测试31

    A. coin

    分析

    设带某种礼物 (x) 件的贡献是 (f(x)) 那么有 (f(x+2)−f(x+1) leq f(x+1)−f(x))

    那么就是说每多一件礼物,收益是递减的

    所以开一个堆,维护 ((i,j,w)) 表示第 (i) 种礼物选第 (j) 份的收益是 (w)

    贪心的选最大的就好了

    问题在于求出 (w)

    (f(k,c,n)) 表示对于前 (n) 个人第 (k) 种礼物一共有 (c) 份的贡献

    (w=f(i,j,n)−f(i,j−1,n))

    直接 (dp)(n^2m)

    但是可以发现有用的不是很多,所以把 (dp) 的形式改成记忆化搜索,需要的时候再搜

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<map>
    #include<vector>
    #include<queue>
    #define rg register
    inline int read(){
    	rg int x=0,fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=3e3+5,maxm=3e2+5;
    int n,m;
    double p[maxn][maxm],ans;
    std::vector<double> g[maxm][maxn];
    double getf(rg int k,rg int c,rg int nn){
    	while(nn && !p[nn][k]) nn--;
    	if(c==0 || !nn) return 0;
    	if(g[k][c][nn]) return g[k][c][nn];
    	return g[k][c][nn]=(getf(k,c-1,nn-1)+1)*p[nn][k]+getf(k,c,nn-1)*(1.0-p[nn][k]);
    }
    struct jie{
    	int num,tim;
    	double val;
    	jie(){}
    	jie(rg int aa,rg int bb,rg double cc){
    		num=aa,tim=bb,val=cc;
    	}
    	bool operator <(const jie& A)const{
    		return val<A.val;
    	}
    };
    std::priority_queue<jie> q;
    int main(){
    	n=read(),m=read();
    	for(rg int i=1;i<=n;i++){
    		for(rg int j=1;j<=m;j++){
    			p[i][j]=read();
    			p[i][j]/=1000.0;
    		}
    	}
    	for(rg int i=1;i<=m;i++){
    		g[i][0].resize(n+1),g[i][1].resize(n+1);
    		q.push(jie(i,1,getf(i,1,n)));
    	}
    	rg int aa,bb;
    	rg double cc;
    	for(rg int i=1;i<=n;i++){
    		aa=q.top().num,bb=q.top().tim,cc=q.top().val;
    		q.pop();
    		ans+=cc;
    		g[aa][bb+1].resize(n+1);
    		q.push(jie(aa,bb+1,getf(aa,bb+1,n)-getf(aa,bb,n)));
    	}
    	printf("%.10f
    ",ans);
    	return 0;
    }
    

    B. B

    分析

    把问题转化一下,要求的就是与给定树重合边数 (geq n−1−k) 的树的个数

    众所周知矩阵树求的是这个

    (sum_{T}prod_{ein T}w_e)

    把原树中的边权设为 (x),其它的边权设为 (1)

    代入矩阵树定理得到的是一个多项式

    多项式的 (k) 次方项的系数就是重合边为 (k) 条时的答案

    多项式显然是一个 (n-1) 次多项式

    可以代入 (n) 项求出值,然后用高斯消元算出系数

    这样做复杂度是 (n^4)

    口胡一下 (n^2) 的做法

    首先钦定 (k) 条边重合,那么可以用二项式反演得到恰好有 (k) 条边重合的方案

    有一个结论 :设有 (m) 个连通块,每个连通块大小分别为 (size_i),生成树个数就是 (n^{m-2} prod limits_{i=1}^m size_i)

    发现后面 (size) 的乘积不好处理

    考虑 (prodlimits_{i=1}^msize_i) 的组合意义,我们可以视为将树划分为若干个联通块,每个联通块内放入一个特殊点的方案数

    改变一下 (dp) 定义,(dp_{i,j,0/1}) 表示 (i) 子树中,划分了 (j) 个连通块,最后一个连通块是否选择了特殊点

    这样复杂度就是 (n^2)

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<map>
    #include<vector>
    #define rg register
    inline int read(){
    	rg int x=0,fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=55,mod=998244353;
    inline int addmod(rg int now1,rg int now2){
    	return now1+=now2,now1>=mod?now1-mod:now1;
    }
    inline int delmod(rg int now1,rg int now2){
    	return now1-=now2,now1<0?now1+mod:now1;
    }
    inline int mulmod(rg long long now1,rg int now2){
    	return now1*=now2,now1>=mod?now1%mod:now1;
    }
    inline int ksm(rg int ds,rg int zs){
    	rg int nans=1;
    	while(zs){
    		if(zs&1) nans=mulmod(nans,ds);
    		ds=mulmod(ds,ds);
    		zs>>=1;
    	}
    	return nans;
    }
    int mp[maxn][maxn],e[maxn][maxn],ans[maxn],tmp[maxn][maxn],n,m;
    int solve(rg int val){
    	for(rg int i=1;i<=n;i++){
    		for(rg int j=1;j<=n+1;j++){
    			mp[i][j]=0;
    		}
    	}
    	for(rg int i=1;i<=n;i++){
    		for(rg int j=i+1;j<=n;j++){
    			if(e[i][j]){
    				mp[i][i]=addmod(mp[i][i],val);
    				mp[j][j]=addmod(mp[j][j],val);
    				mp[i][j]=delmod(mp[i][j],val);
    				mp[j][i]=delmod(mp[j][i],val);
    			} else {
    				mp[i][i]=addmod(mp[i][i],1);
    				mp[j][j]=addmod(mp[j][j],1);
    				mp[i][j]=delmod(mp[i][j],1);
    				mp[j][i]=delmod(mp[j][i],1);
    			}
    		}
    	}
    	rg int nans=1;
    	for(rg int i=2;i<=n;i++){
    		for(rg int j=i+1;j<=n;j++){
    			if(!mp[i][i] && mp[j][i]){
    				std::swap(mp[i],mp[j]);
    				nans=delmod(0,nans);
    				break;
    			}
    		}
    		rg int ny=ksm(mp[i][i],mod-2);
    		for(rg int j=i+1;j<=n;j++){
    			rg int tmp=mulmod(ny,mp[j][i]);
    			for(rg int k=i;k<=n+1;k++) mp[j][k]=delmod(mp[j][k],mulmod(mp[i][k],tmp));
    		}
    	}
    	for(rg int i=2;i<=n;i++) nans=mulmod(nans,mp[i][i]);
    	return nans;
    }
    int main(){
    	n=read(),m=read();
    	rg int aa;
    	for(rg int i=2;i<=n;i++){
    		aa=read()+1;
    		e[i][aa]=e[aa][i]=1;
    	}
    	for(rg int i=1;i<=n;i++){
    		for(rg int j=1;j<=n;j++){
    			tmp[i][j]=ksm(i,j-1);
    		}
    		tmp[i][n+1]=solve(i);
    	}
    	for(rg int i=1;i<=n;i++){
    		for(rg int j=1;j<=n+1;j++){
    			mp[i][j]=tmp[i][j];
    		}
    	}
    	for(rg int i=1;i<=n;i++){
    		rg int ny=ksm(mp[i][i],mod-2);
    		for(rg int j=i;j<=n+1;j++) mp[i][j]=mulmod(mp[i][j],ny);
    		for(rg int j=i+1;j<=n;j++){
    			rg int tmp=mp[j][i];
    			for(rg int k=i;k<=n+1;k++) mp[j][k]=delmod(mp[j][k],mulmod(mp[i][k],tmp));
    		}
    	}
    	ans[n]=mp[n][n+1];
    	for(rg int i=n-1;i>=1;i--){
    		ans[i]=mp[i][n+1];
    		for(rg int j=i+1;j<=n;j++){
    			ans[i]=delmod(ans[i],mulmod(ans[j],mp[i][j]));
    		}
    	}
    	rg int sum=0;
    	for(rg int i=n-m;i<=n;i++) sum=addmod(sum,ans[i]);
    	printf("%d
    ",sum);
    	return 0;
    }
    

    C. battery

    分析

    发现不确定的只有炮台的方向

    而炮台的方向只有两种,所以可以看成一个 (2-SAT) 问题

    因为炮台之间不能相互攻击,所以合法的情况下一个空地最多只能由两个炮台经过

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<map>
    #include<vector>
    #define rg register
    inline int read(){
    	rg int x=0,fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=105,maxm=1e4+5,dx[6]={1,-1,0,0},dy[6]={0,0,1,-1};
    int h[maxm],tot=1;
    struct asd{
        int to,nxt;
    }b[maxm];
    void ad(rg int aa,rg int bb){
        b[tot].to=bb;
        b[tot].nxt=h[aa];
        h[aa]=tot++;
    }
    int dfn[maxm],low[maxm],dfnc,sta[maxm],tp,shuyu[maxm],js;
    void tar(rg int xx){
        dfn[xx]=low[xx]=++dfnc;
        sta[++tp]=xx;
        for(rg int i=h[xx];i!=-1;i=b[i].nxt){
            rg int u=b[i].to;
            if(!dfn[u]){
                tar(u);
                low[xx]=std::min(low[xx],low[u]);
            } else if(!shuyu[u]){
                low[xx]=std::min(low[xx],dfn[u]);
            }
        }
        if(low[xx]==dfn[xx]){
            js++;
            while(1){
                rg int y=sta[tp--];
                shuyu[y]=js;
                if(y==xx) break;
            }
        }
    }
    int t,n,m,rk1[maxn][maxn],rk2[maxn][maxn],vx1[maxm],vx2[maxm],vy1[maxm],vy2[maxm],cnt1,cnt2,jud,haha;
    std::vector<int> g[maxm],tmp;
    char s[maxn][maxn];
    void dfs(rg int nx,rg int ny,rg int d){
        if(s[nx][ny]=='#' || nx>n || nx<1 || ny>m || ny<1 || !jud) return;
        else if(s[nx][ny]=='.'){
            tmp.push_back(rk2[nx][ny]);
            dfs(nx+dx[d],ny+dy[d],d);
        } else if(s[nx][ny]=='\'){
            dfs(nx+dx[d^2],ny+dy[d^2],d^2);
        } else if(s[nx][ny]=='/'){
            dfs(nx+dx[3-d],ny+dy[3-d],3-d);
        } else {
            jud=0;
        }
    }
    int main(){
        t=read();
        while(t--){
            memset(h,-1,sizeof(h));
            memset(dfn,0,sizeof(dfn));
            memset(low,0,sizeof(low));
            memset(shuyu,0,sizeof(shuyu));
            for(rg int i=1;i<=cnt2;i++) g[i].clear();
            tot=haha=1,dfnc=tp=js=cnt1=cnt2=0;
            n=read(),m=read();
            for(rg int i=1;i<=n;i++) scanf("%s",s[i]+1);
            for(rg int i=1;i<=n;i++){
                for(rg int j=1;j<=m;j++){
                    if(s[i][j]=='.'){
                        cnt2++;
                        vx2[cnt2]=i,vy2[cnt2]=j,rk2[i][j]=cnt2;
                    } else if(s[i][j]=='-' || s[i][j]=='|'){
                        cnt1++;
                        vx1[cnt1]=i,vy1[cnt1]=j,rk1[i][j]=cnt1;
                    }
                }
            }
            rg int tmp1=0,tmp2=0;
            for(rg int i=1;i<=n;i++){
                for(rg int j=1;j<=m;j++){
                    if(s[i][j]=='|' || s[i][j]=='-'){
                        tmp1=tmp2=0,jud=1;
                        tmp.clear(),dfs(i+1,j,0);
                        dfs(i-1,j,1);
    					if(jud) for(rg int o=0;o<tmp.size();o++) g[tmp[o]].push_back(rk1[i][j]);
                        tmp1=jud,jud=1;
                        tmp.clear(),dfs(i,j+1,2);
                        dfs(i,j-1,3);
    					if(jud) for(rg int o=0;o<tmp.size();o++) g[tmp[o]].push_back(rk1[i][j]+cnt1);
                        tmp2=jud;
                        if(!tmp1 && !tmp2) haha=0;
                        if(!tmp1){
                            ad(rk1[i][j],rk1[i][j]+cnt1);
                        } 
                        if(!tmp2){
                            ad(rk1[i][j]+cnt1,rk1[i][j]);
                        }
                    }
                }
            }
            for(rg int i=1;i<=cnt2;i++){
                if(g[i].size()==0) haha=0;
                else if(g[i].size()==1){
                    if(g[i][0]>cnt1) ad(g[i][0]-cnt1,g[i][0]);
                    else ad(g[i][0]+cnt1,g[i][0]);
                } else {
                    if(g[i][0]>cnt1) ad(g[i][0]-cnt1,g[i][1]);
                    else ad(g[i][0]+cnt1,g[i][1]);
                    if(g[i][1]>cnt1) ad(g[i][1]-cnt1,g[i][0]);
                    else ad(g[i][1]+cnt1,g[i][0]);
                }
            }
            for(rg int i=1;i<=cnt1+cnt1;i++){
                if(!dfn[i]) tar(i);
            }
            for(rg int i=1;i<=cnt1;i++) if(shuyu[i]==shuyu[i+cnt1]) haha=0;
            if(!haha) printf("IMPOSSIBLE
    ");
            else {
                printf("POSSIBLE
    ");
                for(rg int i=1;i<=cnt1;i++){
                    if(shuyu[i]>shuyu[i+cnt1]) s[vx1[i]][vy1[i]]='-';
                    else s[vx1[i]][vy1[i]]='|';
                }
                for(rg int i=1;i<=n;i++) s[i][m+1]='';
                for(rg int i=1;i<=n;i++) printf("%s
    ",s[i]+1);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    ARM开发工具软件命令具体解释---嵌入式回归第三篇
    Java模拟公司置办货物系统(二)
    springmvc mybatis 声明式事务管理回滚失效,(checked回滚)捕捉异常,传输错误信息
    Django Drops
    从 &quot;org.apache.hadoop.security.AccessControlException:Permission denied: user=...&quot; 看Hadoop 的用户登陆认证
    iOS中Storyboard使用要点记录
    ACdream 1084 寒假安排(阶乘素因子分解)
    【死磕Java并发】-----J.U.C之AQS:CLH同步队列
    使用freemarker做邮件发送模板
    springboot 使用freemarker自定义标签
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/14453636.html
Copyright © 2011-2022 走看看