码迷,mamicode.com
首页 > 其他好文 > 详细

1012

时间:2019-10-13 12:39:47      阅读:60      评论:0      收藏:0      [点我收藏+]

标签:mes   return   前缀   while   tchar   之间   mod   n+1   排序   

期望得分 200
实际得分 174
话说这个第三题sub都没有... 不好骗分啊
A 排 座位
( ( arrange .pas/c/cpp)
【问题描述】
信竞队有 n 名队员,竞赛机房有一张长桌,上面一字排开有 n 台电脑,供同学们坐成一
排使用。每学期开始前,老师都要给同学们排座位。
同学之间存在仰慕(膜拜)关系,如 A 同学仰慕 B 同学,那么 A 同学就要求座位必须与 B
同学相邻。同学之间存在 m 对仰慕关系。老师想要找到使得所有同学的要求都得到满足座位
安排方案。请你帮忙计算合法方案的总数,答案可能很大,mod 989999 后再输出。

主要说一下判环的问题
首先注意到一条边的环只用在读入的时候判断一下就行了
然后对于环不是一条边的情况 我们只需要在加进集合里的时候判断是不是在一个集合就行了
也可以用top排序求环

//
#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define  mod 989999
#define maxnn 1000010
typedef pair<int,int > P;
map<P,int > mm;
ll n,m;
int r[maxnn];
int f[maxnn];
int ru[maxnn];
ll cnt1=1,cnt2;
ll size[maxnn];
#define GC getchar()
inline ll R()
{
    char t;
    ll f=1;
    ll x=0;
    t=GC;
    while(!isdigit(t)) {if(t=='-') f=-1;t=GC;}
    while(isdigit(t)) 
    {
        x=x*10+t-'0';
        t=GC;
    }
    return x*f;
}
int gf(int v)
{
    return f[v]==v?v:f[v]=gf(f[v]);
}
ll jie(ll v)
{
    ll tmp=1;
    for(int i=1;i<=v;i++)
    {
        tmp=(tmp*i)%mod;
    }
    return tmp%mod;
}
void FIE()
{
    freopen("arrange.in","r",stdin);
    freopen("arrange.out","w",stdout);
}
int main()
{
    //FIE();
    n=R();
    m=R();
    ll x,y;
    for(int i=1;i<=n;i++)
    {
        f[i]=i;
        size[i]=1;
    }
    for(int i=1;i<=m;i++)
    {
        x=R();
        r[x]=R();
        int y=r[x];
        if(r[r[x]]==x) continue;
        ru[y]++;
        ru[x]++;
        if(ru[x]>2||ru[y]>2) 
        {
            puts("0");
            return 0;
        }
        int fx=gf(x);
        int fy=gf(y);
        if(fx!=fy)
        {
            size[fy]+=size[fx];
            f[fx]=fy;
        }
        else
        {
            puts("0");
            return 0;
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(f[i]==i)
        {
            if(size[i]>1) cnt1=(cnt1*2)%mod;;
            cnt2++;
        }
    }    
    cout<<(jie(cnt2)*cnt1)%mod;
 } 

B 数列截段
时间限制 : - MS 空间限制 : - KB
评测说明 : 1s,256m
问题描述
老师给出一个长度为N的整数数列A。现在要求你在A中截取一段连续子序列,使得该区间的数字总和不小于X,并且不大于Y。问总共有多少种不同的截取方式?

想到用前缀和+树状数组离散化
式子可以表示为 x<=sum[j]-sum[i-1]<=y
先求x<=sum[j]-sum[i-1] 然后容斥一下减去y<sum[j]-sum[i-1]的方案之和即为答案
code:

//
#include<bits/stdc++.h>
using namespace std;
#define maxnn 500000
#define ll long long 
#define lowbit(i) i&(-i)
ll sum[maxnn];
ll n,x,y;
int id[maxnn];
ll zh[maxnn];
ll c[maxnn];
ll tr=0;
#define GC getchar()
inline ll R()
{
    char t;
    ll f=1;
    ll x=0;
    t=GC;
    while(!isdigit(t)) {if(t=='-') f=-1;t=GC;}
    while(isdigit(t)) 
    {
        x=x*10+t-'0';
        t=GC;
    }
    return x*f;
}
void add(int x)
{
    for(int i=x;i<=3*n+100000;i+=lowbit(i))
    {
        c[i]++;
    }
}
ll get(int x)
{
    ll ans=0;
    for(int i=x;i;i-=lowbit(i))
    {
        ans+=c[i];
    }
    return ans;
}
void FIE()
{
    freopen("cutout.in","r",stdin);
    freopen("cutout.out","w",stdout);
}
int main()
{
    //FIE();
    ll t=0;
    ll ans=0;
    n=R();
    x=R();
    y=R();
    for(int i=1;i<=n;i++)
    {
        t=R();
        sum[i]=sum[i-1]+t;
        tr++;
        sum[n+tr]=sum[i]-x;
        tr++;
        sum[n+tr]=sum[i]-y;
        zh[i]=sum[i];
    }
    sort(sum,sum+1+n+tr);
    int r=unique(sum,sum+1+n+tr)-sum-1;
    for(int i=0;i<=n;i++)
    {
        id[i]=lower_bound(sum,sum+1+r,zh[i])-sum+1;
    }
    for(int i=0;i<=n;i++)
    {
        ll tmp1=lower_bound(sum,sum+1+r,zh[i]-x)-sum+1;
        ans+=get(tmp1);
        ll tmp2=lower_bound(sum,sum+1+r,zh[i]-y)-sum+1;
        ans=ans-get(tmp2-1);
        add(id[i]);
    }
    printf("%lld",ans);
}

1012

标签:mes   return   前缀   while   tchar   之间   mod   n+1   排序   

原文地址:https://www.cnblogs.com/OIEREDSION/p/11665890.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!