【NOIP2011TG】solution

老师最近叫我把NOIPTG的题目给刷掉,于是就开始刷吧= =

链接:https://www.luogu.org/problem/lists?name=&orderitem=pid&tag=83%2C28

D1T1:carpet

题意简析:一个平面内有多个矩形按顺序覆盖平面,问覆盖后某个点属于哪个矩形。

解题思路:从n~1倒着check点有没有在矩形内即可,时间效率\( O(n) \)。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#define For(i,a,b) for (int i=a; i<=b; i++)
#define Ford(i,a,b) for (int i=a; i>=b; i--)
#define File(fn) freopen(fn".in","r",stdin); freopen(fn".out","w",stdout);
#define mem(qaq,num) memset(qaq,num,sizeof(qaq));
#define ll long long
#define mod 1000000007
#define INF 2000000000
using namespace std;
struct zxy{
    int a,b,x,y;
}rect[10001];
int n,x,y;
inline int in(){
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9') f=ch=='-'?-1:1,ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int main(){
    n=in();
    For(i,1,n)
        rect[i].a=in(),rect[i].b=in(),rect,rect[i].x=in()+rect[i].a,rect[i].y=in()+rect[i].b;
    x=in(),y=in();
    Ford(i,n,1){
        if (x>=rect[i].a&&x<=rect[i].x&&y>=rect[i].b&&y<=rect[i].y){
            printf("%d",i);
            return 0;
        }
    }
    printf("-1");
}

 

D1T2:hotel

题意简析:给你n个客栈,叫你选取任意2个色调相同的不同客栈,且它们之间(包括本身)所有的客栈内存在最低消费不超过p的咖啡店,问你有多少种方案。

解题思路:这题貌似有\( O(n) \)的算法,但是我只想到\( O(n^2) \)的贪心,然后用线段树存区间最小值优化一个log,然后存下不同色调的客栈数,顺推一下就行了。时间效率\( O(n \lg n) \).

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#define For(i,a,b) for (int i=a; i<=b; i++)
#define Ford(i,a,b) for (int i=a; i>=b; i--)
#define File(fn) freopen(fn".in","r",stdin); freopen(fn".out","w",stdout);
#define mem(qaq,num) memset(qaq,num,sizeof(qaq));
#define ll long long
#define mod 1000000007
#define INF 2000000000
#define mid ((l+r)>>1)
using namespace std;
int mi[600000],color[50][200000],cnt[50],lst[50],n,k,p;
inline int in(){
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9') f=ch=='-'?-1:1,ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
inline void update(int x,int k,int l,int r,int add){
    if (l==r) {
        mi[k]=add;
        return;
    }
    if (x<=mid) update(x,k<<1,l,mid,add);
    else update(x,k<<1|1,mid+1,r,add);
    mi[k]=min(mi[k<<1],mi[k<<1|1]);
}
inline int query(int l,int r,int k,int a,int b){
    if (!(l^a||r^b)) return mi[k];
    if (b<=mid) return query(l,mid,k<<1,a,b);
    if (a>mid) return query(mid+1,r,k<<1|1,a,b);
    return min(query(l,mid,k<<1,a,mid),query(mid+1,r,k<<1|1,mid+1,b));
}
int main(){
    mem(mi,127/3);
    n=in(),k=in(),p=in();
    For(i,1,n){
        int cl=in(),x=in();
        color[cl][++cnt[cl]]=i;
        update(i,1,1,n,x);
    }
    ll ans=0;
    For(i,0,k-1)
        For(j,2,cnt[i]){
            if (query(1,n,1,color[i][j-1],color[i][j])<=p) ans+=j-1,lst[i]=j-1;
            else ans+=lst[i];
        }
    printf("%lld",ans);
}

 

D1T3:mayan

题意简析:看题目:)

解题思路:这种数据范围,就是爆搜啊= =,暴力枚举每次交换的点,然后按题意模拟一下,就行了。小剪枝:当任意一种颜色不足3个时就return。时间效率O(能过)。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define For(i,a,b) for (int i=a; i<=b; i++)
#define Ford(i,a,b) for (int i=a; i>=b; i--)
#define File(fn) freopen(fn".in","r",stdin); freopen(fn".out","w",stdout);
#define ll long long
#define mod 1000000007
#define INF 2000000000
#define mem(qaq,num) memset(qaq,num,sizeof(qaq));
struct zxy{
    short x,y,op;
}ans[6];
short pq[5][7],n;
inline short in(){
    short x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9') f=ch=='-'?-1:1,ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
inline void swap(short &a,short &b){
    short t=a;a=b,b=t;
}
inline void print(int x,char ch){
    if (!x){
       putchar('0');
       putchar(ch);
       return;
    }
    if (x<0){
       putchar('-');
       x*=-1;
    }
    char num[20];
    short cnt=0;
    while(x) num[++cnt]=x%10+'0',x/=10;
    while(cnt) putchar(num[cnt--]);
    putchar(ch);
}
void output(){
    For(i,1,n) print(ans[i].x,' '),print(ans[i].y,' '),print(ans[i].op,'\n');
    exit(0);
}
inline void down(){
    For(i,0,4){
        short pos=0;
        For(j,0,6)
            if (pq[i][j]) pq[i][pos++]=pq[i][j];
        For(j,pos,6) pq[i][j]=0;
    }
}
inline bool check(){
    For(i,0,4) For(j,0,6) if (pq[i][j]) return 0;
    return 1;
}
inline bool move(){
    bool flag=0,used[5][7]={0};
    For(i,0,4)
        For(j,0,6){
            if (i<3&&pq[i][j]==pq[i+1][j]&&pq[i][j]==pq[i+2][j]&&pq[i][j]){
                used[i][j]=used[i+1][j]=used[i+2][j]=1;
                flag=1;
            }
            if (j<5&&pq[i][j]==pq[i][j+1]&&pq[i][j]==pq[i][j+2]&&pq[i][j]){
                used[i][j]=used[i][j+1]=used[i][j+2]=1;
                flag=1;
            }
        }
    For(i,0,4)
        For(j,0,6)
            if (used[i][j]) pq[i][j]=0;
    return flag;
}
inline void dfs(int k){
    if (k>n) if (check()) output(); else return;    
    int memory[5][7],cnt[11]={0};
    For(i,0,4) For(j,0,6) ++cnt[pq[i][j]];
    For(i,1,10) if (cnt[i]<3&&cnt[i]) return;
    memcpy(memory,pq,sizeof(pq));
    For(x,0,3)
        For(y,0,6)
            if(pq[x][y]!=pq[x+1][y]){
                if (pq[x][y]) ans[k].x=x,ans[k].y=y,ans[k].op=1;
                else ans[k].x=x+1,ans[k].y=y,ans[k].op=-1;
                swap(pq[x][y],pq[x+1][y]);
                down();while(move()) down();
                dfs(k+1);
                memcpy(pq,memory,sizeof(pq));
            }
}
int main(){
    n=in();
    For(i,0,4){
        short pos=0,x=in();
        while(x) pq[i][pos++]=x,x=in();
    }
    dfs(1);
    printf("-1\n");
}

 

D2T1:factor

题意简析:就是题目要求的啊。

解题思路:把ax和by看成整体,杨辉三角形求完全k次方式的各项系数,然后再用ax和by代进去就行了。时间效率\( O(k^2) \)。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#define For(i,a,b) for (int i=a; i<=b; i++)
#define Ford(i,a,b) for (int i=a; i>=b; i--)
#define File(fn) freopen(fn".in","r",stdin); freopen(fn".out","w",stdout);
#define mem(qaq,num) memset(qaq,num,sizeof(qaq));
#define ll long long
#define mod 10007
#define INF 2000000000
using namespace std;
int tri[1002][1002],n,m,k,a,b;
inline int in(){
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9') f=ch=='-'?-1:1,ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
inline int ksm(int a,int k){
    if (!k) return 1;
    if (!(k^1)) return a%mod;
    int ans=ksm(a,k/2)%mod;
    if (k&1) return ans*ans%mod*a%mod;
    return ans*ans%mod;
}
int main(){
    a=in()%mod,b=in()%mod,k=in(),n=in(),m=in();
    tri[1][1]=1;
    For(i,2,k+1)
        For(j,1,i)
            tri[i][j]=(tri[i-1][j-1]+tri[i-1][j])%mod;
    printf("%d",ksm(a,n)*ksm(b,m)%mod*tri[k+1][k-n+1]%mod);
}

 

D2T2:qc

题意简析:叫你确定一个参数W按照公式计算后使得|S-∑y[i]|最小。

解题思路:显然对于W的递增,有∑y[i]单调递减,我们考虑二分W,然后进行check。这样的效率是\( O(nm \lg S)\)的,我们可以发现我们可以通过每次2分后进行一个O(n)的预处理,计算≥W的个数与总和前缀,这样就可以优化效率。时间效率\( O((n+m) \lg max{W[i]}) \)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#define For(i,a,b) for (int i=a; i<=b; i++)
#define Ford(i,a,b) for (int i=a; i>=b; i--)
#define File(fn) freopen(fn".in","r",stdin); freopen(fn".out","w",stdout);
#define mem(qaq,num) memset(qaq,num,sizeof(qaq));
#define mod 1000000007
#define INF 1e18
#define mid (l+r>>1)
using namespace std;
int cnt[200001],sum[200001],w[200001],n,m,ll[200001],rr[200001],maw,miw=0x7fffffff,v[200001];
long long s,ans=1e18;
template <class T>
inline void in(T &x){
    x=0;
    short f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9') f=ch=='-'?-1:1,ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    x*=f;
}
void init(int k){
    cnt[0]=sum[0]=0;
    For(i,1,n)
        if (w[i]>=k){
            cnt[i]=cnt[i-1]+1;
            sum[i]=sum[i-1]+v[i];
        }
        else cnt[i]=cnt[i-1],sum[i]=sum[i-1];
    return;
}
inline void BS(int l,int r){
    if (l>r) return;
    init(mid);
    long long tmp=0;
    For(i,1,m){
        tmp+=abs((long long)((cnt[rr[i]]-cnt[ll[i]-1])*(sum[rr[i]]-sum[ll[i]-1])));
        if (tmp>INF) break;
    }
    if (tmp==s){
        ans=0;
        return;
    }
    if (tmp<s){
        if (s-tmp<ans){
            ans=s-tmp;
        }
        BS(l,mid-1);
        return;
    }
    if (tmp-s<ans){
        ans=tmp-s;
    }
    BS(mid+1,r);
}
int main(){
    in(n); in(m); in(s);
    For(i,1,n)
        in(w[i]),in(v[i]),miw=miw>w[i]?w[i]:miw,maw=maw<w[i]?w[i]:maw;
    For(i,1,m)
        in(ll[i]),in(rr[i]);
    BS(miw,maw);
    printf("%lld",ans);
}

 

D2T3:bus

题意:就是一条链,每个点之间有限定条件,叫你求权值最小是多少。

解题思路:枚举每个加速器放在哪里,用前缀和优化找出对于可能的加速可以减少多少等待时间即可。时间效率\( O(kn) \)。(貌似有\( O(n) \)的算法)

#include<stdio.h>
#define For(i,a,b) for (int i=a; i<=b; i++)
#define Ford(i,a,b) for (int i=a; i>=b; i--)
#define File(fn) freopen(fn".in","r",stdin); freopen(fn".out","w",stdout);
#define ll long long
#define mod 1000000007
#define INF 2000000000
int n,m,k,num[1001],st[1001],tim[1001],dis[1001],ans,use[1001]; 
struct zxy{
    int a,b,t;
}tou[10001];
template <class T>
inline void in(T &x){
    x=0;
    short f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    x*=f;
}
template <class T>
inline void print(T x,char ch){
    if (!x){
       putchar('0');
       putchar(ch);
       return;
    }
    if (x<0){
       putchar('-');
       x*=-1;
    }
    char num[20];
    short cnt=0;
    while(x) num[++cnt]=x%10+'0',x/=10;
    while(cnt) putchar(num[cnt--]);
    putchar(ch);
}//for integer only
template <class T>
inline T max(T a,T b){
    return a>b?a:b;
}
template <class T>
inline T min(T a,T b){
    return a<b?a:b;
}
template <class T>
inline void abs(T &x){
    x=x<0?-x:x;
}
void init(){
    in(n),in(m),in(k);
    For(i,1,n-1) in(dis[i]);
    For(i,1,m)
        in(tou[i].t),in(tou[i].a),in(tou[i].b),num[tou[i].b]++,st[tou[i].a]=max(tou[i].t,st[tou[i].a]);
    For(i,2,n) num[i]+=num[i-1];
    tim[1]=0;
    For(i,2,n)
        tim[i]=max(tim[i-1],st[i-1])+dis[i-1];
    For(i,1,m)
        ans+=tim[tou[i].b]-tou[i].t;
}
void solve(){
    while(k){
        use[n]=use[n-1]=n;  
        Ford(i,n-2,1)
            use[i]=tim[i+1]<=st[i+1]?i+1:use[i+1];
        int np=0,p;
        For(i,1,n)
            if (num[use[i]]-num[i]>np&&dis[i])
                np=num[use[i]]-num[i],p=i;
        if (!np) break;
        ans-=np;
        dis[p]--;
        k--;
        tim[1]=0;
        For(i,2,n)
            tim[i]=max(tim[i-1],st[i-1])+dis[i-1];
    }
    print(ans,'\n');
}
int main(){
    init();
    solve();
    return 0;
}

 本文由Melacau编写,Melacau代表M星向您问好,如果您不是在我的博客http://www.cnblogs.com/Melacau上看到本文,请您向我联系,email:13960948839@163.com.

posted @ 2017-03-13 11:37  Melacau  阅读(222)  评论(0编辑  收藏  举报