• 2018.8.28 练习赛


    T1 机房排座

    机房排座

    题解:

    有解的充要性条件:

    1.任意一个班级的同学个数不能多于机房空位置数的一半
    2.我们把机房的格子进行黑白染色。按班级人数由多到少落座。先坐白色格子,再坐黑色格子。

    样例2:

    code:

    #include<stdio.h>
    #include<bits/stdc++.h>
    using namespace std;
    int n,m,k,maxx=0,i,j,t=1,r[102][102];
    struct node
    {
    	int id,num;
    	bool operator<(const node &u)const{return u.num<num;}
    }a[10002];
    int main()
    {
    	scanf("%d%d%d",&n,&m,&k);
    	for(i=1;i<=k;i++)
    	{
    		scanf("%d",&a[i].num);
    		maxx=max(maxx,a[i].num);
    		a[i].id=i;
    	}
    	sort(a+1,a+k+1);
    	if(maxx*2>n*m+1)
    	{
    		for(i=1;i<=n;i++)
    		{
    			for(j=1;j<=m;j++)printf("0 ");
    			putchar('
    ');
    		}
    		return 0;
    	}
    	if(m&1)
    	{
    		for(i=0;i<n*m;i+=2)
    		{
    			r[i/m+1][i%m+1]=a[t].id;
    			a[t].num--;
    			if(a[t].num==0)t++;
    		}
    		for(i=1;i<n*m;i+=2)
    		{
    			r[i/m+1][i%m+1]=a[t].id;
    			a[t].num--;
    			if(a[t].num==0)t++;
    		}
    	}
    	else
    	{
    		for(i=0;i<n*m;i+=2)
    		{
    			r[i/m+1][i%m+1+((i/m)&1)]=a[t].id;
    			a[t].num--;
    			if(a[t].num==0)t++;
    		}
    		for(i=1;i<n*m;i+=2)
    		{
    			r[i/m+1][i%m+1-((i/m)&1)]=a[t].id;
    			a[t].num--;
    			if(a[t].num==0)t++;
    		}
    	}
    	for(i=1;i<=n;i++)
    	{
    		for(j=1;j<=m;j++)printf("%d ",r[i][j]);
    		putchar('
    ');
    	}
    	return 0;
    }
    

    T2 大佬玩游戏

    大佬玩游戏

    题解:

    对于第(i)个人,设被整除的概率为(p[i]),则与他相邻的(i+1)个人与他之积能被整除的概率为(p[x]=p[i]+p[j]-p[i]*p[j]),因此,(ans=sum(2000*p[x]))

    code:

    #include<stdio.h>
    #include<algorithm>
    #include<ctype.h>
    #define val 2000
    #define ld double
    #define ll long long
    using namespace std;
    
    char buf[1<<20],*p1,*p2;
    inline char gc() {
    	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
    }
    
    template<typename T>
    void read(T &x) {
    	char tt;
    	bool flag=0;
    	while(!isdigit(tt=gc())&&tt!='-');
    	tt=='-'?(x=0,flag=1):(x=tt-'0');
    	while(isdigit(tt=gc())) x=x*10+tt-'0';
    	if(flag) x=-x;
    }
    
    ll n,k;
    ld ans;
    ld p[100005];
    int main() {
    	read(n),read(k);
    	for(int i=1; i<=n; i++) {
    		ll x,y;
    		read(x),read(y);
    		p[i]=1.0*(y/k-(x-1)/k)/(y-x+1);
    	}
    	for(int i=1; i<=n; i++)
    		ans+=(p[i]+p[(i+1)>n?1:i+1]-p[i]*p[(i+1)>n?1:i+1])*val;
    	printf("%lf",ans);
    }
    

    T3 方块消除

    方块消除

    题解:

    从左往右读入方块,读到某数字第一次出现的时候记录位置L,第二次出现的时候位置(R),统计在((L,R))区间没有被消除掉的方块的个数K。那么消除(L),(R)这一对方块需要进行(K)次交换。然后将(L)(R)消除掉。
    我们需要记录([L,R])区间中未消除的方块的个数,用树状数组。
    当某数字(x)第一次出现时,设出现的位置为(L)。我们标记(Pos[x]=L)。并把它加入树状数组(Modify(x,1))
    当数字(x)第二次出现时,设出现位置为(R)。我们统计((L,R))区间未被消除的数字个数(K)。用树状数组进行区间查询即可。(K=getSum[R]-getSum(Pos[x]-1));(ans+=k);
    然后消除掉(L)(R),即(Modify(Pos[x],-1))

    code:

    #include<stdio.h>
    #include<algorithm>
    #include<ctype.h>
    #define ll long long
    using namespace std;
    
    char buf[1<<20],*p1,*p2;
    inline char gc() {
    	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
    }
    
    template<typename T>
    void read(T &x) {
    	char tt;
    	bool flag=0;
    	while(!isdigit(tt=gc())&&tt!='-');
    	tt=='-'?(x=0,flag=1):(x=tt-'0');
    	while(isdigit(tt=gc())) x=x*10+tt-'0';
    	if(flag) x=-x;
    }
    
    ll n;
    ll ans;
    ll a[1000005];
    ll c[1000005];
    ll pos[1000005];
    bool book[1000005];
    
    ll lowbit(ll x) {
    	return x&-x;
    }
    
    void modify(ll x,ll d) {
    	for(ll i=x; i<=1000000; i+=lowbit(i))
    		c[i]+=d;
    }
    
    ll getsum(ll x) {
    	ll tmp=0;
    	for(ll i=x; i; i^=lowbit(i))
    		tmp+=c[i];
    	return tmp;
    }
    
    int main() {
    	read(n);
    	for(ll i=1; i<=(n<<1); i++) {
    		read(a[i]);
    		if(book[a[i]]) {
    			ans+=getsum(i)-getsum(pos[a[i]]);
    			modify(pos[a[i]],-1);
    		} else book[a[i]]=1,pos[a[i]]=i,modify(i,1);;
    	}
    	printf("%lld",ans);
    }
    

    T4 财务信息

    财务信息

    题解:

    考虑使用并查集来维护前缀和:

    (s[i]=a[1]+a[2]+...+a[i]),即(s[i])为前缀和。
    (v[i]=s[i]-s[fa[i]]),其中(fa[i])(i)的父亲。
    对于每个读入的(x,y,z),将(x,y)视为结点:

    1. 如果(x,y)的根结点相同,即(fa[x]==fa[y]),又因为(v[y]-v[x]=s[y]-s[fa[y]]-(s[x]-s[fa[x]])=s[y]-s[x]),所以(v[y]-v[x])就是区间([x,y])的和,所以只需要判断(v[y]-v[x])是否等于(z)就可以了。
    2. 如果(x)(y)的根结点不相同,合并两个节点并更新信息:
      将y合并到(x)所在集合,(x)的根变为(y)的根的父亲(v[fa[y]]=v[x]+z-v[y])(a[fa[y]]=fa[x])

    code:

    #include<cstdio>
    #include<iostream>
    using namespace std;
    int n,m,x,y,z,u,v,cas;
    int f[105],dis[105];
    int a[1005],b[1005],c[1005];
    int get(int x)
    {
        if(f[x]==x) return x;
        int t=f[x];
        f[x]=get(f[x]);
        dis[x]=dis[x]+dis[t];
        return f[x];
    }
    int main()
    {
        cin>>cas;
        while(cas--) 
        {
            cin>>n>>m;
            for(int i=0;i<=n;i++) 
            {
                f[i]=i;
                dis[i]=0;
            }
            int ok=0;
            for(int i=1;i<=m;i++) scanf("%d%d%d",&a[i],&b[i],&c[i]);
            for(int i=1;i<=m;i++) 
            {
                x=a[i],y=b[i],z=c[i];
                x--;
                u=get(x);
                v=get(y);
                if(u==v) 
                {
                    if(dis[y]-dis[x]!=z) 
                    {
                        ok=1;
                        cout<<"false"<<endl;
                        break;
                    }
                }
                else
                {
                    f[v]=u;
                    dis[v]=dis[x]-dis[y]+z;
                }
            }
            if(ok==0) cout<<"true"<<endl;
        }
        return 0;
    }
    
  • 相关阅读:
    良心之作送你几个Xsheel使用小技巧
    面试问Redis集群,被虐的不行了......
    一文搞定Redis五大数据类型及应用场景
    写给大忙人的Redis主从复制,花费五分钟让你面试不尴尬
    Redis删除策略和逐出策略
    一文带你了解Redis持久化完整版本
    MySQL--创建计算字段
    MySQL语句与正则表达式
    SQLZOO练习二--SELECT from Nobel Tutorial
    SQLZOO练习(一)SELECT BASICS,SELECT form world
  • 原文地址:https://www.cnblogs.com/KatouKatou/p/9549531.html
Copyright © 2020-2023  润新知