1. 程式人生 > >[NOIP2011]刷水

[NOIP2011]刷水

using 處理 can include 處理方法 ans 過去 urn pri

  前幾天做了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]刷水