好题随缘题解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;
}
原文地址:https://www.cnblogs.com/BlankAo/p/14157982.html