zoukankan      html  css  js  c++  java
  • 好题随缘题解2020Dec

    - 目录 -

    orz / 按照这个题单刷的

    可乐 / 物流运输 / 区间加区间sin和


    可乐

    解法

    停留相当于给自己点建一个自环,然后走这条边。

    自爆相当于建一个大点 (n+1) ,所有点向大点连向一个有向边,这样就有去无回了!

    (所以如果现在机器人panda在东京上野的动物园这个地方自爆,那么我们就要对它说再见了)

    大点的自环只是延续了状态,并不代表连续自爆。

    考虑矩阵乘法。设一个矩阵 (large A_{i,j}) 代表从 (i) 刚好走一步到 (j) 的方案数。

    则转移类似 ( exttt{Floyd}) 的过程, (B_{i,j}=sumlimits_{k=1}^{n+1}A_{i,k}*A_{k,j}) 这就过于显然的矩阵乘法了。

    (large A^2_{i,j}) 代表从 (i) 刚好走两步到 (j) 的方案数。

    所以 (large A^t) 就是最后我们需要的,答案就是 (sumlimits_{i=1}^{n+1} A^t_{1,i})

    所以大点的自环也是有用的。

    代码

    #include<bits/stdc++.h>
    #define rep(i,x,y) for(int i=x;i<=y;i++)
    using namespace std;
    const int n7=33,mo=2017;
    struct dino{int tix[n7][n7];}lead,ans;
    int n,m,t,fin;
    
    dino operator * (dino p,dino q){
    	dino tot;memset(tot.tix,0,sizeof tot.tix);
    	rep(i,1,n+1)rep(k,1,n+1)rep(j,1,n+1){
    		tot.tix[i][j]=(tot.tix[i][j]+p.tix[i][k]*q.tix[k][j])%mo;
    	}
    	return tot;
    }
    
    int rd(){
       int shu=0;char ch=getchar();
       while(!isdigit(ch))ch=getchar();
       while(isdigit(ch))shu=(shu<<1)+(shu<<3)+ch-'0',ch=getchar();
       return shu;
    }
    
    int main(){
    	n=rd(),m=rd();
    	rep(i,1,n+1)lead.tix[i][i]=lead.tix[i][n+1]=1;
    	rep(i,1,m){
    		int sta=rd(),edn=rd();
    		lead.tix[sta][edn]=lead.tix[edn][sta]=1;
    	}
    	t=rd();
    	rep(i,1,n+1)ans.tix[i][i]=1;
    	while(t){
    		if(t&1)ans=ans*lead;
    		lead=lead*lead;
    		t=t>>1;
    	}
    	rep(i,1,n+1)fin=(fin+ans.tix[1][i])%mo;
    	printf("%d",fin);
    	return 0;
    }
    

    物流运输

    解法

    因为数据小,所以可以乱搞~

    我们设 (f_i)(1sim i) 天的最小花费,(g_{i,j})(isim j) 天都走一条路的最小花费。

    那么明显有 (f_i=min{ g_{1,i},minlimits_{j=1}^if_{j-1}+g_{i,j}+ m{rmb}})

    或是从第一天到第 (i) 天都走一条路,不花修改的费用;或是从某一天往后修改,花费修改的费用。

    然后怎么求出 (g_{i,j})

    很简单,把 (isim j) 的封闭的道路都封闭,然后跑一遍最短路就行啦。(肯定是最短路而不是其它的路径,因为要求最优解)

    代码

    #include<bits/stdc++.h>
    #define rep(i,x,y) for(int i=x;i<=y;i++)
    #define die(x,y) memset(x,y,sizeof x)
    using namespace std;
    const int n7=22,t7=123,inf=16843009;
    struct dino{int id,disz;};
    bool operator < (dino p,dino q){return p.disz>q.disz;}
    int t,n,m,rmb,f[t7],g[t7][t7],ez[t7][n7][n7],e[n7][n7],dis[n7];
    bool vis[n7];
    
    int rd(){
       int shu=0;char ch=getchar();
       while(!isdigit(ch))ch=getchar();
       while(isdigit(ch))shu=(shu<<1)+(shu<<3)+ch-'0',ch=getchar();
       return shu;
    }
    
    void dij(){
    	die(dis,1),die(vis,0),dis[1]=0;
    	priority_queue <dino> que;
    	que.push( (dino){1,0} );
    	while(!que.empty()){
    		int o=que.top().id;que.pop();
    		if(vis[o])continue;
    		vis[o]=1;
    		rep(v,1,n){
    			if(dis[v]<=dis[o]+e[o][v])continue;
    			dis[v]=dis[o]+e[o][v];
    			if(!vis[v])que.push( (dino){v,dis[v]} );
    		}
    	}
    }
    
    int main(){
    	t=rd(),n=rd(),rmb=rd(),m=rd();
    	die(ez,1);
    	rep(i,1,m){
    		int sta=rd(),edn=rd(),w=rd();
    		if(ez[0][sta][edn]>w){
    			ez[0][sta][edn]=ez[0][edn][sta]=w;
    			rep(i,1,t)ez[i][sta][edn]=ez[i][edn][sta]=w;
    		}
    	}
    	int tnp=rd();
    	rep(i,1,tnp){
    		int id=rd(),l=rd(),r=rd();
    		rep(j,l,r)rep(k,1,n)ez[j][id][k]=ez[j][k][id]=inf;
    	}
    	rep(L,1,t){
    		rep(i,1,n)rep(j,1,n)e[i][j]=ez[L][i][j];
    		rep(R,L,t){
    			rep(i,1,n)rep(j,1,n)if(ez[R][i][j]==inf)e[i][j]=inf;
    			dij(),g[L][R]=dis[n]*(R-L+1);
    		}
    	}
    	rep(R,1,t){
    		f[R]=g[1][R];
    		rep(L,1,R)f[R]=min(f[R],f[L-1]+g[L][R]+rmb);
    	}
    	printf("%d",f[t]);
    	return 0;
    }
    

    区间加区间sin和

    换了个新的pushidown写法(汗)

    解法

    和角公式。线段树维护sin和cos。

    代码

    #include<bits/stdc++.h>
    #define rep(i,x,y) for(int i=x;i<=y;++i)
    #define lod long double
    #define lon long long
    #define ert 1,1,n
    #define lsn o<<1,l,mid
    #define rsn o<<1|1,mid+1,r
    using namespace std;
    const int n7=201234,t7=801234;
    int n,T,a[n7];lod tre1[t7],tre2[t7];lon laz[t7];
    
    int rd(){
    	int shu=0;char ch=getchar();
    	while(!isdigit(ch))ch=getchar();
    	while(isdigit(ch))shu=(shu<<1)+(shu<<3)+ch-'0',ch=getchar();
    	return shu;
    }
    
    void plant(int o,int l,int r){
    	if(l==r){
    		tre1[o]=sin(a[l]),tre2[o]=cos(a[l]);
    		return;
    	}
    	int mid=(l+r)>>1;
    	plant(lsn),plant(rsn);
    	tre1[o]=tre1[o<<1]+tre1[o<<1|1];
    	tre2[o]=tre2[o<<1]+tre2[o<<1|1];
    }
    
    void modif(int o,lon x){
    	lod sinz=tre1[o],cosz=tre2[o];
    	tre1[o]=cos(x)*sinz+sin(x)*cosz;
    	tre2[o]=cos(x)*cosz-sin(x)*sinz;
    	laz[o]+=x;
    }
    
    void updat(int o,int l,int r,int L,int R,int x){
    	if(L<=l&&r<=R){modif(o,x);return;}
    	modif(o<<1,laz[o]);
    	modif(o<<1|1,laz[o]);
    	laz[o]=0;
    	int mid=(l+r)>>1;
    	if(L<=mid)  updat(lsn,L,R,x);
    	if(R>=mid+1)updat(rsn,L,R,x);
    	tre1[o]=tre1[o<<1]+tre1[o<<1|1];
    	tre2[o]=tre2[o<<1]+tre2[o<<1|1];
    }
    
    lod query(int o,int l,int r,int L,int R){
    	if(L<=l&&r<=R)return tre1[o];
    	modif(o<<1,laz[o]);
    	modif(o<<1|1,laz[o]);
    	laz[o]=0;
    	int mid=(l+r)>>1;lod tot=0;
    	if(L<=mid)  tot+=query(lsn,L,R);
    	if(R>=mid+1)tot+=query(rsn,L,R);
    	return tot;
    }
    
    int main(){
    	n=rd();
    	rep(i,1,n)a[i]=rd();
    	plant(ert);
    	T=rd();
    	while(T--){
    		int sys=rd();
    		if(sys==1){
    			int l=rd(),r=rd(),w=rd();
    			updat(ert,l,r,w);
    		}
    		if(sys==2){
    			int l=rd(),r=rd();
    			printf("%.1Lf
    ",query(ert,l,r));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    将个人博客与github关联
    docker镜像制作
    perf命令
    vmstat命令
    ps命令
    top命令
    linux查看当前用户登陆信息
    .NET CORE应用程序启动
    WebAPI简介
    Redis-位图
  • 原文地址:https://www.cnblogs.com/BlankAo/p/14157982.html
Copyright © 2011-2022 走看看