zoukankan      html  css  js  c++  java
  • 2018.7.15模拟赛

    今天真是个奇奇怪怪的考试。。。盲人OI+智障OI=HSZOI
    T1:(出题人英语水平堪忧)
    不会写正解,写的暴力水一下。。。谁曾想有个咸鱼搞错了a,b,x,y的正确关系????80->40???
    暴力80解,留个纪念,纪念本咸鱼首次(希望最后一次)写错变量名:

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    
    int exgcd(int a,int b,int &x,int &y) {
    	if(!b) {x=1,y=0;return a;}
    	int tp=exgcd(b,a%b,y,x);
    	y=y-(a/b)*x;
    	return tp;
    }
    int T,a,b,c;
    int main() {
    	freopen("fuction.in","r",stdin);
    	freopen("fuction.out","w",stdout);
    	scanf("%d",&T);
    	while(T--) {
    		int x,y;
    		scanf("%d%d%d",&a,&b,&c);
    		if(a<b) swap(a,b);
    		if(a<0&&b<0&&c<0) a=-a,b=-b,c=-c;
    		if(a<0&&b<0&&c>0) {puts("0");continue;}
    		if(a>0&&b>0&&c<0) {puts("0");continue;}
    		if(a+b>c) {puts("0");continue;}
    		if(a+b==c) {
    			puts("1");
    			continue;
    		}
    		if(a==1&&b==1) {
    				if(c-1>65535)
    				printf("ZenMeZheMeDuo
    ");
    				else printf("%d
    ",c-1);
    			continue;
    		}
    		int cnt=0;
    		for(int i=1;i*a<c;i++) {
    			int tp=c-i*a;
    			if(tp%b==0) cnt++;
    			if(cnt>65535) break;
    		}
    		if(cnt>65535) puts("ZenMeZheMeDuo");
    		else printf("%d
    ",cnt);
    	}
    }
    //3
    //-1 -1 -3
    //1 1 65536
    //1 1 65537
    

    正解:扩欧求方程一组x最小,y最大的解。
    代码有注释

    #include <iostream>
    #include <cstdio>
    #define int long long
    using namespace std;
    void exgcd(int a,int b,int c,int &x,int &y,int &d) {
    	if(!b) {
    		d=a;
    		y=0;
    		x=c/a;
    		return;
    	}
    	exgcd(b,a%b,c,y,x,d);
    	y-=(a/b)*x;
    }
    main() {
    	int T,a,b,c;
    	scanf("%lld",&T);
    	while(T--) {
    		bool f1=0,f2=0;
    		scanf("%lld%lld%lld",&a,&b,&c);
    		if(c<0) a=-a,b=-b,c=-c;
    		if(a==0&&b==0) {
    			if(c==0) puts("ZenMeZheMeDuo");
    			else puts("0");
    			continue;
    		}
    		int x,y,gcd;
    		if(a<0) a=-a,f1=1;//exgcd不能处理负数
    		if(b<0) b=-b,f2=1;
    		exgcd(a,b,c,x,y,gcd);
    		if(a*x+b*y!=c) {puts("0");continue;}
    		if(f1) x=-x,a=-a;
    		if(f2) y=-y,b=-b;
    		if(a==0) {
    			if(y<=0) puts("0");
    			else puts("ZenMeZheMeDuo");
    			continue;
    		}
    		if(b==0) {if(x<=0)puts("0");else puts("ZenMeZheMeDuo");continue;}
    		if((a>0&&b<0)||(a<0&&b>0)) {puts("ZenMeZheMeDuo");continue;}
    		if(a<0) a=-a,b=-b,c=-c;
    		a/=gcd,b/=gcd,c/=gcd;
    		x%=b;//ax+by=c的一组解,将x缩到最小正数后y的解
    		int ans=0;
    		if(x<=0) x+=b;
    		y=(c-a*x)/b;
    		int miny=y%a;//求miny->y之间有多少种合法解。
    		if(miny<=0) miny+=a;
    		if(miny>y)ans=0;
    		else ans=(y-miny)/a+1;
    		if(ans>65535) puts("ZenMeZheMeDuo");
    		else printf("%lld
    ",ans);
    	}
    }
    //3
    //-1 -1 -3
    //1 1 65536
    //1 1 65537
    

    T2
    我真的是。。。
    没错今天是个奇奇怪怪的考试,又一次变量名搞错。。。难道是昨天被篮球砸了一下脑子不正常了???
    正解:树形dp,每个子树上的点必定和别的点有一条边经过该子树与其父节点的边。据此列出状态转移方程即可。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #define int long long
    using namespace std;
    const int N=2005;
    int n,m,f[N][N],head[N],ecnt,siz[N],tp[N];
    struct Edge {
        int to,nxt,val;
    } e[N<<1];
    void add(int bg,int ed,int val) {
        e[++ecnt].nxt=head[bg];
        e[ecnt].to=ed;
        e[ecnt].val=val;
        head[bg]=ecnt;
    }
    void dfs(int x,int fa) {
        siz[x]=1;
        for(int i=head[x]; i; i=e[i].nxt) {
            int v=e[i].to;
            if(v==fa) continue;
            dfs(v,x);
            memset(tp,0,sizeof tp);
            for(int k=0;k<=min(siz[x],m);k++) {
                for(int j=0;j<=min(siz[v],m-k)&&k+j<=m;j++) {
                    tp[k+j]=max(tp[k+j],f[x][k]+f[v][j]+e[i].val*((m-j)*j+(n-m-siz[v]+j)*(siz[v]-j)));
                }
            }
            for(int j=0;j<=m;j++) f[x][j]=max(f[x][j],tp[j]);
            siz[x]+=siz[v];
        }
    }
    signed  main() {
        scanf("%lld%lld",&n,&m);
        for(int i=1,a,b,c; i<n; i++) {
            scanf("%lld%lld%lld",&a,&b,&c);
            add(a,b,c);
            add(b,a,c);
        }
        dfs(1,0);
        cout<<f[1][m];
    }
    /*
    3 1
    1 2 1
    1 3 2
    */
    

    T3
    并不正确的暴力(教师机10,本机20Orz)
    我也懒得调了。。。正解貌似是一个优秀的模拟,什么曼哈顿距离转切比雪夫距离...

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    using namespace std;
    int n,m,k,g[1005][1005],sx,sy,dx,dy,f[1005][1005][4];
    const int mp[3][3]= {1,-1,0,-1,-1,-1,3,-1,2};
    int main() {
    	freopen("ray.in","r",stdin);
    	freopen("ray.out","w",stdout);
    	scanf("%d%d%d",&n,&m,&k);
    	for(int i=1,x,y; i<=k; i++) {
    		scanf("%d%d",&x,&y);
    		g[x][y]=1;
    	}
    	scanf("%d%d",&sx,&sy);
    	char dir[5];
    	scanf("%s",dir);
    	if(dir[0]=='N') {
    		dx=-1;
    		dir[1]=='E'?dy=1,f[sx][sy][0]=1:dy=-1,f[sx][sy][1]=1;
    	} else {
    		dx=1;
    		dir[1]=='E'?dy=1,f[sx][sy][2]=1:dy=-1,f[sx][sy][3]=1;
    	}
    	for(int i=0;i<=n+1;i++) g[i][0]=1,g[i][m+1]=1;
    	for(int i=0;i<=m+1;i++) g[0][i]=1,g[n+1][i]=1;
    	while(1) {
    		int nx=dx+sx,ny=dy+sy;
    		if(f[nx][ny][mp[dx+1][dy+1]]) break;
    		bool flag=0;
    		if(g[nx][ny]) {
    			flag=1;
    			if(mp[dx+1][dy+1]==0) {
    				if(g[nx+1][ny]&&!g[nx][ny-1]) dy=-dy,sx--;
    				else if((g[nx+1][ny]&&g[nx][ny-1])||(!g[nx+1][ny]&&!g[nx][ny-1])) dx=-dx,dy=-dy,sx+=dx,sy=dy;
    				else if(g[nx][ny-1]) dx=-dx,sy++;
    			} else if(mp[dx+1][dy+1]==1) {
    				if(g[nx+1][ny]&&!g[nx][ny+1]) dy=-dy,sx--;
    				else if((g[nx+1][ny]&&g[nx][ny+1])||(!g[nx+1][ny]&&!g[nx][ny+1])) dx=-dx,dy=-dy,sx+=dy,sy+=dy;
    				else if(g[nx][ny+1]) dx=-dx,sy--;
    			} else if(mp[dx+1][dy+1]==2) {
    				if(g[nx-1][ny]&&!g[nx][ny-1]) dy=-dy,sx++;
    				else if((g[nx-1][ny]&&g[nx][ny-1])||(!g[nx-1][ny]&&!g[nx][ny-1])) dx=-dx,dy=-dy,sx+=dx,sy+=dy;
    				else if(g[nx][ny-1]) dx=-dx,sy++;
    			} else if(mp[dx+1][dy+1]==3) {
    				if(g[nx+1][ny]&&!g[nx][ny-1]) dy=-dy,sx+=dx;
    				else if((g[nx+1][ny]&&g[nx][ny-1])||(!g[nx+1][ny]&&!g[nx][ny-1])) dx=-dx,dy=-dy,sx+=dx,sy+=dy;
    				else if(g[nx][ny+-1]) dx=-dx,sy+=dy;
    			}
    		}
    		if(!flag) sx+=dx,sy+=dy;
    		if(f[sx][sy][mp[dx+1][dy+1]]) break;
    		f[sx][sy][mp[dx+1][dy+1]]=1;
    	}
    	int cnt=0;
    	for(int i=1; i<=n; i++) {
    		for(int j=1; j<=m; j++) {
    			if(f[i][j][0]||f[i][j][1]||f[i][j][2]||f[i][j][3]) cnt++;
    		}
    	}
    	cout<<cnt;
    }
    /*
    7 5 3
    3 3
    4 3
    5 3
    2 1 SE
    */
    

    60pts:(和我的思路有什么区别)

    #include <map>
    #include <set>
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #define x first
    #define y second
    #define pii pair<int,int>
    using namespace std;
    typedef long long ll;
    const int N=100005;
    int n,m,k,ans;
    char ss[5];
    set<pii>bl,em;
    map<pii,set<pii> >vis;
    pii s,t,dir;
    int main() {
    	scanf("%d%d%d",&n,&m,&k);
    	for(int i=0;i<=n+1;i++) bl.insert(pii(i,m+1)),bl.insert(pii(i,0));
    	for(int i=0;i<=m+1;i++) bl.insert(pii(n+1,i)),bl.insert(pii(0,i));
    	for(int i=1,x,y;i<=k;i++) scanf("%d%d",&x,&y),bl.insert(pii(x,y));
    	scanf("%d%d",&s.x,&s.y);
    	scanf("%s",ss);
    	dir.x=(ss[0]=='N'?-1:1);
    	dir.y=(ss[1]=='W'?-1:1);
    	while(1) {
    		if(em.insert(s).y) ans++;
    		t=pii(s.x+dir.x,s.y+dir.y);
    		if(!bl.count(t)) s=t;
    		else {
    			if(!vis[t].insert(dir).y) break;
    			int x=bl.count(pii(t.x-dir.x,t.y)),y=bl.count(pii(t.x,t.y-dir.y));
    			if(x==y) dir.x=-dir.x,dir.y=-dir.y;
    			else if(x) s.x+=dir.x,dir.y=-dir.y;
    			else s.y+=dir.y,dir.x=-dir.x;
    		}
    	}
    	cout<<ans;
    }
    

    100pts:

    //强啊。。。 
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <map>
    #include <set>
    #define int long long
    using namespace std;
    int n,m,k;
    int ans;
    bool flag;
    const int N=100005;
    map<int,int> mp;
    map<int,set<int> >A,B;
    bool ck(int x,int y) {return mp[x*N+y];}
    void work(int dx,int dy,int x,int y) {
    	int sx=x,sy=y,nx,ny;
    	bool f=1;
    	set<int>::iterator it;
    	bool bx,by;
    	while(1) {
    		if(dx+dy) 
    			it=A[x-y].lower_bound(x);//哪个对角线上 
    		else it=B[x+y].lower_bound(x);
    		if(dx==1) nx=*it-1;
    		else it--,nx=*it+1;//如果是后退,lower_bound后就找到的不是第一个障碍物,而是下一个。 
    		ny=y+dx*dy*(nx-x);//变得横坐标与变得纵坐标差的是个正负。 
    		if(!f&&((sx-x)*(sx-nx)<=0&&((x-y==nx-ny&&x-y==sx-sy)||(x+y==nx+ny&&x+y==sx+sy)))){ans+=abs(sx-x);return;}
    /*不是第一次运动&&x坐标重复经过过原点(强啊)
    (因为可能会因为lower_bound跨越原来的原点)
    &&x,y与原点在一条对角线上*/
    		ans+=abs(nx-x)+1;//经过的格子数 
    		bx=ck(nx+dx,ny),by=ck(nx,ny+dy);//这个点处于3个块夹的或只有一个块 (就是要反弹了)(因为lower_bound找到它的路径上第一个方块) 
    		if((bx&&by)||(!bx&&!by)) {flag=1;return;}
    		if(bx) dx=-dx,ny+=dy;
    		if(by) dy=-dy,nx+=dx;
    		x=nx,y=ny;
    		f=0;
    	}
    }
    void ins(int  x,int y) {
    	mp[x*N+y]=1;
    	A[x-y].insert(x);B[x+y].insert(x);
    }
    int read(){
    		//懒得写快读。 
    }
    main() {
    	int sx,sy,dx,dy;
    	char opt[5];
    	scanf("%lld%lld%lld",&n,&m,&k);
    	for(int i=0;i<=n+1;i++) ins(i,0),ins(i,m+1);
    	for(int j=0;j<=m+1;j++) ins(0,j),ins(n+1,j);
    	for(int i=1,x,y;i<=k;i++) scanf("%lld%lld",&x,&y),ins(x,y);
    	scanf("%lld%lld%s",&sx,&sy,opt);
    	if(opt[0]=='N') dx=-1;else dx=1;
    	if(opt[1]=='W') dy=-1;else dy=1;
    	work(dx,dy,sx,sy);
    	if(flag) work(-dx,-dy,sx,sy),ans--;
    	printf("%lld",ans);
    }
    

    总结:
    注意保护视力Orz。。。
    写完题不要划水,再检查一下。。。

    我是咸鱼。转载博客请征得博主同意Orz
  • 相关阅读:
    flex + bison multiple parsers
    Educational Codeforces Round 95 (Rated for Div. 2)
    python学习笔记 day20 序列化模块(二)
    python学习笔记 day20 常用模块(六)
    python 学习笔记 常用模块(五)
    python学习笔记 day19 常用模块(四)
    python学习笔记 day19 常用模块(三)
    python学习笔记 day19 常用模块(二)
    python学习笔记 day19 作业讲解-使用正则表达式实现计算器
    python学习笔记 day19 常用模块
  • 原文地址:https://www.cnblogs.com/sdfzhsz/p/9313630.html
Copyright © 2011-2022 走看看