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('\n');
		}
		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('\n');
	}
	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;
}
posted @ 2018-08-28 17:10  Katoumegumi  阅读(81)  评论(0编辑  收藏  举报
返回顶部