[NOIP2011]刷水

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[NOIP2011]刷水相关的知识,希望对你有一定的参考价值。

  前几天做了NOIP2011的题,感觉不是那么难。

  这边先做了两天的前两题,T3还没打。

D1T1:顺次读入,分别判断是否覆盖即可,照例大水:

#include<cstdio>
int x,y,a[10001],b[10001],c[10001],d[10001],n,ans=-1;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d%d%d%d",a+i,b+i,c+i,d+i);
    scanf("%d%d",&x,&y);
    for(int i=1;i<=n;i++)
        if(a[i]<=x&&b[i]<=y&&c[i]+a[i]>=x&&d[i]+b[i]>=y)ans=i;
    printf("%d",ans);
    return 0;
}

D1T2:一边扫过去,对于每家客栈,我们记下前一家相同色调的客栈,前一家能去的咖啡店,之前有多少家可以和这间客栈搭配和这是第几间该色调的客栈,然后如果前一家色调相同的客栈编号在前一家能去的咖啡店之前,说明这之前的客栈都能去,把可搭配客栈数更新后加入答案,否则直接加入答案。

代码如下:

#include<cstdio> 
using namespace std; 
int n,p,t[200001],h[51],ans,l[51],lst[51]; 
int main() 
{ 
    scanf("%d%*d%d",&n,&p); 
    for(int i=0;i<=50;i++)lst[i]=1; 
    for(int i=1;i<=n;i++) 
    { 
        int w,c; 
        scanf("%d%d",&c,&w); 
        t[i]=t[i-1]+(w<=p); 
        if(t[i]!=t[lst[c]-1])h[c]=l[c]; 
        l[c]++; 
        ans+=h[c]; 
        if(w<=p)h[c]=l[c]; 
        lst[c]=i; 
    } 
    printf("%d",ans); 
    return 0; 
}

D2T1:用杨辉三角计算组合数然后用二项式定理直接出解:

#include<cstdio>
const int mod=10007;
int a,b,k,n,m,C[1002][1002],aa=1,bb=1;
void calC()
{
    C[1][1]=1;
    for(int i=2;i<=1001;i++)
        for(int j=1;j<=i;j++)
            C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
int main()
{
    calC();
    scanf("%d%d%d%d%d",&a,&b,&k,&n,&m);
    a%=mod;b%=mod;
    for(int i=1;i<=n;i++)aa=(aa*a)%mod;
    for(int i=1;i<=m;i++)bb=(bb*b)%mod;
    printf("%d",((aa*bb%mod)*C[k+1][n+1])%mod);
    return 0;
}

D2T2:使和标准最近,而且是单调递减,容易想到用二分答案+check

二分就不说了。check中我们要O(m)计算m个区间的sigma,可以对于二分出的x计算从1到n能加入答案的计算前缀和然后轻松处理。

要注意防止爆long long,这边处理方法是加个最优上限maxn,否则一定不优。

代码如下:

#include<cstdio>
const long long maxn=10000000000000ll;
long long mn(long long x,long long y){return x<y?x:y;}
long long s[200001],ans=maxn,sa,v[200001],w[200001],sum[200001],l[200001],r[200001],ll,rr,n,m,mid;
bool check(long long x)
{
    long long tt=0;
    for(int i=1;i<=n;++i)
        sum[i]=sum[i-1]+(w[i]>=x),
        s[i]=s[i-1]+(w[i]>=x?v[i]:0);
    for(int i=1;i<=m;++i)
    {
        tt+=(sum[r[i]]-sum[l[i]-1])*(s[r[i]]-s[l[i]-1]);
        if(tt>maxn)return 0;
    }
    ans=mn(-mn(tt-sa,sa-tt),ans);
    return tt<=sa;
}
void bina()
{
    ll=0;rr=1000000;
    while(ll<rr)
    {
        mid=(ll+rr)/2;
        check(mid)?rr=mid:ll=mid+1;
    }
}
int main()
{
    scanf("%lld%lld%lld",&n,&m,&sa);
    for(int i=1;i<=n;++i)scanf("%lld%lld",w+i,v+i);
    for(int i=1;i<=m;++i)scanf("%lld%lld",l+i,r+i);
    bina();
    check(mid-1);check(mid);
    printf("%lld",ans);
    return 0;
}

 

以上是关于[NOIP2011]刷水的主要内容,如果未能解决你的问题,请参考以下文章

几道莫名AC的并查集题

刷水题

NOIp 2011 mayan游戏 搜索

[NOIP2011]聪明的质监员 题解

[NOIP2011]观光公交 题解

P1307 [NOIP2011 普及组] 数字反转