好题随缘题解2020Dec
- 目录 -
可乐
解法
停留相当于给自己点建一个自环,然后走这条边。
自爆相当于建一个大点 \(n+1\) ,所有点向大点连向一个有向边,这样就有去无回了!
(所以如果现在机器人panda在东京上野的动物园这个地方自爆,那么我们就要对它说再见了)
大点的自环只是延续了状态,并不代表连续自爆。
考虑矩阵乘法。设一个矩阵 \(\large A_{i,j}\) 代表从 \(i\) 刚好走一步到 \(j\) 的方案数。
则转移类似 \(\texttt{Floyd}\) 的过程, \(B_{i,j}=\sum\limits_{k=1}^{n+1}A_{i,k}*A_{k,j}\) 这就过于显然的矩阵乘法了。
则 \(\large A^2_{i,j}\) 代表从 \(i\) 刚好走两步到 \(j\) 的方案数。
所以 \(\large A^t\) 就是最后我们需要的,答案就是 \(\sum\limits_{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\) 第 \(1\sim i\) 天的最小花费,\(g_{i,j}\) 第 \(i\sim j\) 天都走一条路的最小花费。
那么明显有 \(f_i=\min\{ g_{1,i},\min\limits_{j=1}^if_{j-1}+g_{i,j}+\rm{rmb}\}\)
或是从第一天到第 \(i\) 天都走一条路,不花修改的费用;或是从某一天往后修改,花费修改的费用。
然后怎么求出 \(g_{i,j}\) ?
很简单,把 \(i\sim 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\n",query(ert,l,r));
}
}
return 0;
}