• 9.19 洛谷月赛


    9.19

    洛谷月赛

    (1)雷雨——dij

    啊啊啊差点点想到,还是太菜

    一直想从一个点跑最短路然后$$ dis[1][a]+dis[n][b]+dis[n][c] $$然后复杂度很假,最后摸了整场考试——殊不知这是巨简单的一场

    正解其实是从(1,a) (n,b) (n,c) 每个点为起点跑dij,然后复杂度O(3*n^2) 。。。

    学到了一点:函数里传数组

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    const int N=1005;
    inline int read() {
    	int x=0;char ch=getchar();
    	while(!isdigit(ch)) ch=getchar();
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return x;
    }
    typedef long long LL;
    int n,m,a,b,c;
    LL ans=1e18;//开到1e18,0x3f3f3f3f不够 
    LL A[N][N],B[N][N],C[N][N],val[N][N];
    struct node{
    	int x,y;LL d;
    	node(){}
    	node(int x_,int y_,LL d_):x(x_),y(y_),d(d_){}
    	bool operator < (const node &w) const {
    		return d>w.d;
    	} 
    }; 
    int dx[4]={0,0,-1,1};
    int dy[4]={-1,1,0,0};
    bool vis[N][N]; 
    void dij(int stx,int sty,LL (*dis)[N]) {
    	priority_queue<node>q;
    	memset(vis,0,sizeof(vis));
    	memset(dis,0x3f,sizeof(A));//sizeof
    	dis[stx][sty]=val[stx][sty];
    	q.push(node(stx,sty,dis[stx][sty]));
    	while(!q.empty()) {
    		int x=q.top().x,y=q.top().y; q.pop();
    		if(vis[x][y]) continue;
    		vis[x][y]=1;
    		for(int i=0;i<4;i++) {
    			int xx=x+dx[i],yy=y+dy[i];
    			if(xx>n||xx<1||yy>m||yy<1) continue;
    			if(dis[xx][yy]>dis[x][y]+val[xx][yy])
    				dis[xx][yy]=dis[x][y]+val[xx][yy],q.push(node(xx,yy,dis[xx][yy]));
    		}
    	}
    }
    int main() {
    	n=read();m=read();a=read();b=read();c=read();
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			val[i][j]=read();
    	dij(1,a,A);
    	dij(n,b,B);
    	dij(n,c,C);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			ans=min(ans,A[i][j]+B[i][j]+C[i][j]-val[i][j]*2);
    	printf("%lld
    ",ans);
    	return 0;
    }
    //dij 
    
    

    (2)梦原——权值树状数组

    如果新的点比并上去的点苹果少,那么每次往上并上一个新的点,所产生的代价是0

    如果新的点比并上去的点苹果多,那你就需要多花 多出来的苹果数 那么多,
    那么对于新加的点i,所产生的期望代价就是看[i - k,i - 1]这里面的点哪些点比新点的val少,答案加上差值,然后除k

    这可以用离散化的权值树状数组维护

    具体代码中的a[i]是离散后的排名,c[a[i]]就是原始值

    我们要维护区间 [i-k,i-1]中 sum_a[i]及 其个数siz,产生的代价即为a[now]*siz-sum_a[i];

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <utility>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    const int N=2005000;
    const int P=998244353;
    inline int read() {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    #define MP make_pair
    typedef long long LL;
    int n,m,k;
    int a[N],c[N]; 
    LL inv[N];
    inline void Max(int &x,int y){if(x<y)x=y;}
    inline void Min(int &x,int y){if(x>y)x=y;}
    inline void plu(int &x,int y){x+=y;x>=P&&(x-=P);}
    int ct[N],cd[N];//权值树状数组——个数/和
    inline void upd(int x,int v,int vv) {
    	for(;x<=m;x+=x&(-x)) plu(cd[x],v),ct[x]+=vv;
    }
    inline pair<int,int> query(int x) {
    	int sum=0,siz=0;
    	for(;x;x-=x&(-x)) plu(sum,cd[x]),siz+=ct[x];
    	return MP(sum,siz);
    }
    
    int main() {
    	n=read();k=read();
    	for(int i=1;i<=n;i++) c[i]=a[i]=read();
    	sort(c+1,c+1+n);m=unique(c+1,c+1+n)-c-1;
    	LL ans=a[1];
    	a[1]=lower_bound(c+1,c+1+m,a[1])-c;
    	upd(a[1],c[a[1]],1);
    	
    	inv[0]=inv[1]=1;
    	for(int i=2;i<=k;i++)
    		inv[i]=(P-P/i)*inv[P%i]%P;
    	for(int i=2;i<=n;i++) {
    		if(i-k-1>=1) upd(a[i-k-1],P-c[a[i-k-1]],-1);
    		a[i]=lower_bound(c+1,c+1+m,a[i])-c;
    		pair<int,int> s=query(a[i]);
    		ans=(ans+inv[min(k,i-1)]*(1ll*c[a[i]]*s.second%P-s.first+P)%P)%P;
    		upd(a[i],c[a[i]],1);
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
    
    

    (3)线形生物——期望dp

    大力推式子

    https://www.luogu.com.cn/blog/tyf233/p6835-cnoi2020-xian-xing-sheng-wu

    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    const int N=1e6+5;
    const int P=998244353;
    inline int read() {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    typedef long long LL;
    int id,n,m;
    LL ans,sum[N],f[N];
    vector<int>pre[N];
    int main() {
    	id=read();n=read();m=read(); 
    	for(int i=1,x,y;i<=m;i++) {
    		x=read(),y=read();
    		pre[x].push_back(y);
    	}
    	for(int i=1;i<=n;i++) {
    		for(int j=0;j<pre[i].size();j++) {
    			f[i]=(f[i]+sum[i-1]-sum[pre[i][j]-1]+P)%P;
    		} 
    		f[i]=(f[i]+pre[i].size()+1)%P;
    		sum[i]=(sum[i-1]+f[i])%P;
    	} 
    	printf("%lld
    ",sum[n]);
    	return 0;
    }
    
    
  • 相关阅读:
    求100-999之间所有的水仙花数
    验证用户密码程序
    【bzoj2002】[Hnoi2010]Bounce 弹飞绵羊 分块/LCT
    【bzoj1070】[SCOI2007]修车 最小费用流
    【bzoj3669】[Noi2014]魔法森林 Kruskal+LCT
    【bzoj3668】[Noi2014]起床困难综合症 贪心
    【bzoj1391】[Ceoi2008]order 网络流最小割
    【bzoj4873】[Shoi2017]寿司餐厅 最大权闭合图
    【bzoj1180】[CROATIAN2009]OTOCI LCT
    【bzoj3282】Tree LCT
  • 原文地址:https://www.cnblogs.com/ke-xin/p/13698881.html
Copyright © 2020-2023  润新知