zoukankan      html  css  js  c++  java
  • HZOI20190816模拟23 mine/water/gcd

    A:mine

    只是一个简单的dp。。。。是博主太蒻了。。。

    设f[i][j],表示到第i位,状态是j的方案数,其中$jin[0,5]$

    j==0表示填0,j==1表示填1,且i-1位是雷;

    j==2表示填2,j==3表示填雷,j==5表示填1,且i-1位不是雷

    思考一下,得到方程:

          $f[i][4]=f[i-1][3]$
                $f[i][1]=f[i-1][4]+f[i-1][0]$

          $f[i][3]=f[i-1][1]+f[i-1][2]+f[i-1][3]$
                $f[i][0]=f[i-1][4]+f[i-1][0]$
                $f[i][2]=f[i-1][3]$

    然后就没什么了

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #define int long long
    using namespace std;
    const int MAXN=1e6+1;
    const int mod=1e9+7;
    int len,ans=0,f[2][5];
    char s[MAXN];
    signed main(){
    	scanf("%s",s+1);
    	len=strlen(s+1);
    	if(s[1]=='*') f[1][3]=1;
    	else if(s[1]=='1') f[1][1]=1;
    	else if(s[1]=='0') f[1][0]=1;
    	else if(s[1]=='?') f[1][3]=f[1][1]=f[1][0]=1;
    	for(int i=2;i<=len;i++){
    		f[i&1][0]=f[i&1][1]=f[i&1][2]=f[i&1][3]=f[i&1][4]=0;
    		if(s[i]=='?'){
    			f[i&1][4]=f[i&1^1][3]%mod;
    			f[i&1][1]=(f[i&1^1][4]+f[i&1^1][0])%mod;
    			f[i&1][3]=((f[i&1^1][1]+f[i&1^1][2])%mod+f[i&1^1][3])%mod;
    			f[i&1][0]=(f[i&1^1][4]+f[i&1^1][0])%mod;
    			f[i&1][2]=f[i&1^1][3]%mod;
    		}else if(s[i]=='1'){
    			f[i&1][4]=f[i&1^1][3]%mod;
    			f[i&1][1]=(f[i&1^1][4]+f[i&1^1][0])%mod;
    		}else if(s[i]=='*'){
    			f[i&1][3]=((f[i&1^1][1]+f[i&1^1][2])%mod+f[i&1^1][3])%mod;
    		}else if(s[i]=='0'){
    			f[i&1][0]=(f[i&1^1][4]+f[i&1^1][0])%mod;
    		}else{
    			f[i&1][2]=f[i&1^1][3]%mod;
    		}
    	}
    	ans=((f[len&1][4]+f[len&1][0])%mod+f[len&1][3])%mod;
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    B:water

    一个块的高度就是从这个块走出矩形的所有路径上的最大值的最小值。

    相邻块连边,权值为两块的较大值,矩形边界的块向“矩形外”连边,权值为 max(高度,0),

    做最小生成树,然后每个点的积水高度就是这个点到根节点路径上的最大边权减去这个点的点权

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define MAXN 305
    #define inf 0x7fffffff
    using namespace std;
    int n,m,a[MAXN][MAXN],dep[MAXN*MAXN];
    int calc(int i,int j){
    	return (i-1)*m+j;
    }
    struct node{
    	int fr,to,w,nxt;
    	friend bool operator < (node a,node b){
    		return a.w<b.w;
    	}
    }e[MAXN*MAXN*4],edge[MAXN*MAXN*4];
    int pre[MAXN*MAXN],cnt=0,tot=0;
    void add(int u,int v,int w){
    	cnt++;
    	e[cnt].to=v,e[cnt].fr=u;
    	e[cnt].w=w;
    }
    void ADD(int u,int v,int w){
    	tot++;
    	edge[tot].to=v,edge[tot].fr=u;
    	edge[tot].nxt=pre[u],pre[u]=tot;
    	edge[tot].w=w;
    }
    int fa[MAXN*MAXN];
    int find(int x){
    	return fa[x]==x?x:fa[x]=find(fa[x]);
    }
    void kruskal(){
    	for(int i=1;i<=n*m+1;i++) fa[i]=i;
    	sort(e+1,e+cnt+1);
    	int sum_edge=0,sum=0;
    	for(int i=1;i<=cnt;i++){
    		int x=find(e[i].fr),y=find(e[i].to);
    		if(x!=y){
    			fa[x]=y;
    			ADD(x,y,e[i].w);
    			ADD(y,x,e[i].w);
    			sum_edge++;
    		}
    		if(sum_edge==n*m)
    			break;
    	}
    }
    bool vis[MAXN*MAXN];
    void dfs(int x,int fa){
    	vis[x]=1;
    	for(int i=pre[x];i;i=edge[i].nxt){
    		int y=edge[i].to;
    		if(y==fa) continue;
    		if(vis[y]) continue;
    		dep[y]=max(dep[x],max(dep[y],edge[i].w));
    		dfs(y,x);
    	}
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++){
    			scanf("%d",&a[i][j]);
    		}
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++){
    			if(j+1<=m){
    				add(calc(i,j),calc(i,j+1),max(a[i][j],a[i][j+1]));
    				add(calc(i,j+1),calc(i,j),max(a[i][j],a[i][j+1]));
    			}
    			if(i+1<=n){
    				add(calc(i,j),calc(i+1,j),max(a[i][j],a[i+1][j]));
    				add(calc(i+1,j),calc(i,j),max(a[i][j],a[i+1][j]));
    			}
    		}
    	}
    	for(int i=1;i<=m;i++){
    		add(n*m+1,calc(1,i),max(0,a[1][i]));
    		add(calc(1,i),n*m+1,max(0,a[1][i]));
    		add(n*m+1,calc(n,i),max(0,a[n][i]));
    		add(calc(n,i),n*m+1,max(0,a[n][i]));
    	}
    	for(int i=2;i<n;i++){
    		add(n*m+1,calc(i,1),max(0,a[i][1]));
    		add(calc(i,1),n*m+1,max(0,a[i][1]));
    		add(n*m+1,calc(i,m),max(0,a[i][m]));
    		add(calc(i,m),n*m+1,max(0,a[i][m]));
    	}
    	kruskal();
    	memset(dep,-0x7f,sizeof(dep));
    	dfs(n*m+1,0);
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++){
    			printf("%d ",dep[calc(i,j)]-a[i][j]);
    		}
    		puts("");
    	}
    	return 0;
    }
    

    C:gcd

    并不是gcd,好像有mobius反演的内容,博主先咕了

    不能咕!只知道按着题解说的做,它说啥我做啥

    用 f(i)表示 gcd 为 i 的数对个数,g(i)表示 gcd 为 i 的倍数的数对个数。

    那么$f(i)=sumlimits_dmu(d)*g(d)$,我们只需要维护g(1)~g(max(xi))。

    记 s(i)表示 i 的倍数的个数,那么$g(i)=frac{s(i)*(s(i)-1)}{2}$,

    我们只需要在加入/删除一个数时枚举它的因数修改 s 即可。

    下面放上我的濒临TLE代码:

    第一遍TLE70,原封不动再交一遍就A了

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<queue>
    #include<vector>
    #include<algorithm>
    #define MAXN 200005
    #define MAXX 500005
    #define int long long
    using namespace std;
    int n,m,maxa=0,a[MAXN];
    int prime[MAXX],vis[MAXX],mu[MAXX],tot;
    void get_mu(int n){
        vis[1]=mu[1]=1;
        for(int i=2;i<=n;i++){
            if(!vis[i]) prime[++tot]=i,mu[i]=-1;
            for(int j=1;j<=tot&&i*prime[j]<=n;j++){
                vis[i*prime[j]]=1;
                if(!(i%prime[j])){
                    mu[i*prime[j]]=0;
                    break;
                }
                mu[i*prime[j]]=-mu[i];
            }
        }
    }
    vector<int>d[MAXX];
    bool flag[MAXN];
    int f,g[MAXX],s[MAXX];
    void add(int x){
    	int N=d[x].size();
    	for(int i=0;i<N;i++){
    		int t=d[x][i];
    		s[t]++;
    		f-=mu[t]*g[t];
    		g[t]=s[t]*(s[t]-1)/2;
    		f+=mu[t]*g[t];
    	}
    }
    void del(int x){
    	int N=d[x].size();
    	for(int i=0;i<N;i++){
    		int t=d[x][i];
    		s[t]--;
    		f-=mu[t]*g[t];
    		g[t]=s[t]*(s[t]-1)/2;
    		f+=mu[t]*g[t];
    	}
    }
    signed main(){
    	scanf("%lld%lld",&n,&m);
    	for(int i=1;i<=n;i++){
    		scanf("%lld",&a[i]);
    		maxa=max(maxa,a[i]);
    	}
    	get_mu(maxa);
    	for(int i=1;i<=maxa;i++)
    		for(int j=1;j*i<=maxa;j++)
    			d[i*j].push_back(i);
    	for(int i=1,pos;i<=m;i++){
    		scanf("%lld",&pos);
    		if(!flag[pos]) add(a[pos]);
    		else del(a[pos]);
    		printf("%lld
    ",f);
    		flag[pos]=!flag[pos];
    	}
    	return 0;
    }
    
  • 相关阅读:
    ProcessOn:功能强大的在线作图工具(HTML5)
    jQuery 通用表单方法
    JavaScript中Date的一些细节
    推荐可以代替Visio的HTML开发的作图工具:ProcessOn
    Processon 一款基于HTML5的在线作图工具
    JavaScript编程异步助手:Promise
    【Tsinghua OJ】范围查询(Range)问题
    【Tsinghua OJ】多米诺骨牌(domino)问题
    没有微信的24小时里
    大理:一场风花雪月的事
  • 原文地址:https://www.cnblogs.com/Juve/p/11366021.html
Copyright © 2011-2022 走看看