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
  • 相关阅读:
    java乱码问题解决
    发送邮件工具方法
    MD5加密算法工具类
    2015年4月与5月
    Hark的数据结构与算法练习之煎饼排序
    Hark的数据结构与算法练习之图书馆排序
    Hark的数据结构与算法练习之耐心排序
    Hark的数据结构与算法练习之多路归并排序
    Hark的数据结构与算法练习之若领图排序ProxymapSort
    启动mysql出现了error the server quit without updating pid file (/var/lib/mysql/localhost.localdomain.pid)
  • 原文地址:https://www.cnblogs.com/sdfzhsz/p/9313630.html
Copyright © 2011-2022 走看看