20171023考试总结

辣鸡

题目描述:辣鸡ljh NOI之后就退役了,然后就滚去学文化课了。然而在上化学课的时候,数学和化学都不好的ljh却被一道简单题难住了,受到了大佬的嘲笑。题目描述是这样的:在一个二维平面上有一层水分子,请问形成了多少个氢键?这个二维平面可以看做一个类似棋盘的东西,每个格子可以容纳一个水分子,左下角的格子为(0,0),这个格子右边的格子为(1,0),上方格子为(0,1),以此类推。辣鸡ljh当然不会做了,所以他来求助JeremyGou,JeremyGou一眼就看穿了真相,并想用这道题来考一考正在做NOIP模拟赛的你。注:在本题中,我们认为一个水分子能与和它曼哈顿距离为2且直线距离小于2的其他格子形成氢键。

题解:先处理单独一个矩阵中的氢键2*(a-1)*(b-1);
然后处理矩阵之间的氢键,用两个数组把所有矩阵按x1,x2排序,然后两个变量i,j向滑动窗口一样扫过去处理左右间氢键,再y1,y2排序处理上下间氢键。

分析:细节比较多,本来可以拿75分,然而离散化的数组开小了。。。这种扫描方法确实没想到,用了桶排序的方法碰运气,,,重点还是在于数组开小这种低级错误。。。

#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=100000+10;
struct node{
    int x1,y1,x2,y2;
}mat[N],ret[N];
int n;ll ans;
inline void cal1(node t1,node t2){
    //left and right
    if(t1.x1>t2.x1) swap(t1,t2);
    if(t2.x1-t1.x2==1){
        int y1=max(t1.y1,t2.y1);
        int y2=min(t1.y2,t2.y2);
        if(y2>=y1){
            ans+=(1ll+y2-y1)*2ll;
            if(t1.y1==t2.y1) ans--;
            if(t1.y2==t2.y2) ans--;
        }
    }
}
inline void cal2(node t1,node t2){
    if(t1.y1>t2.y1) swap(t1,t2);
    if(t2.y1-t1.y2==1){
        int x1=max(t1.x1,t2.x1);
        int x2=min(t1.x2,t2.x2);
        if(x2>=x1){
            ans+=(1ll+x2-x1)*2ll;
            if(t1.x1==t2.x1) ans--;
            if(t1.x2==t2.x2) ans--;
        }
    }
}
inline void getint(int&num){
    char c;num=0;
    while((c=getchar())<'0'||c>'9');
    while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
}
bool cmpx1(node a,node b){
    if(a.x1==b.x1) return a.y1else return a.x1bool cmpx2(node a,node b){
    if(a.x2==b.x2) return a.y1else return a.x2bool cmpy1(node a,node b){
    if(a.y1==b.y1) return a.x1else return a.y1bool cmpy2(node a,node b){
    if(a.y2==b.y2) return a.x1else return a.y2int main(){
    //freopen("ljh.in","r",stdin);
    //freopen("ljh.out","w",stdout);
    getint(n);
    for(int i=1;i<=n;i++){
        getint(mat[i].x1),getint(mat[i].y1);
        getint(mat[i].x2),getint(mat[i].y2);
        ret[i]=mat[i];
        int a=mat[i].x2-mat[i].x1+1;
        int b=mat[i].y2-mat[i].y1+1;
        ans+=2ll*(a-1ll)*(b-1ll);
    }

    sort(mat+1,mat+n+1,cmpx2);
    sort(ret+1,ret+n+1,cmpx1);
    for(int i=1,j=1;i<=n&&j<=n;i++){
        for(;j<=n&&ret[j].x11;j++);
        if(j>n) break ;
        for(;j<=n&&ret[j].x1==mat[i].x2+1&&ret[j].y2if(j>n) break ;
        for(;j<=n&&ret[j].x1==mat[i].x2+1&&ret[j].y1<=mat[i].y2;j++)
            cal1(mat[i],ret[j]);
        if(j>1) j--;
    }

    sort(mat+1,mat+n+1,cmpy2);
    sort(ret+1,ret+n+1,cmpy1);
    for(int i=1,j=1;i<=n&&j<=n;i++){
        for(;j<=n&&ret[j].y11;j++);
        if(j>n) break ;
        for(;j<=n&&ret[j].y1==mat[i].y2+1&&ret[j].x2if(ret[j].x2==mat[i].x1-1) ans++;
        if(j>n) break ;
        for(;j<=n&&ret[j].y1==mat[i].y2+1&&ret[j].x1<=mat[i].x2;j++){
            cal2(mat[i],ret[j]);
        }
        if(ret[j].x1==mat[i].x2+1) ans++;
        if(j>1) j--;
    }
    cout</*
3
0 0 0 0
0 1 1 2
2 2 2 3
*/
/*
10
1 8 8 9
0 3 10 7
0 0 7 0
0 2 9 2
4 10 8 10
10 0 10 2
0 10 0 10
8 0 9 1
0 8 0 9
9 8 10 8
*/

模板

20171023考试总结_第1张图片

题解:方法是树上启发式合并,把询问挂在节点上,每访问一个节点先dfs它除重儿子之外的其他儿子,没访问完一个清除此儿子的影响,在访问它的重儿子(不清除影响),时间为O(nlogn),访问一个节点时,用线段树(下标为时间),记录该节点的情况求答案时在线段树上二分。

分析:这是第一次遇到树上启发式合并,没想出来很正常,但是暴力出了点小意外令人尴尬,,,构造数据的时候k[i]=0的情况没有考虑到,然后。。。虽然暴力本来就只有30分但这种。。。尴尬。。。

#include
#include
#include
#include
#include
#include
#define lson x<<1
#define rson x<<1|1
using namespace std;
const int N=100000+10;
const int M=200000+10;
inline void getint(int&num){
    char c;int flag=1;num=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
    num*=flag;
}
map<int,int> color;
vectorint,int> > col[N];
int n,u,v,cnt,m,k[N],siz[N],son[N];
int fir[N],tar[M],nxt[M],ans[N],f[N];
int sum1[N<<2],sum2[N<<2];
bool dele[N<<2];
inline void link(int a,int b){
    tar[++cnt]=b;
    nxt[cnt]=fir[a],fir[a]=cnt;
}
void getson(int x,int fa){
    int Max=0;siz[x]=1;
    for(int i=fir[x];i;i=nxt[i])
        if(tar[i]!=fa){
            getson(tar[i],x);
            siz[x]+=siz[tar[i]];
            if(siz[tar[i]]>Max){
                Max=siz[tar[i]];
                son[x]=tar[i];
            }
        }
}
void pushdown(int x){
    if(dele[x]){
        dele[lson]=dele[rson]=1;
        sum1[lson]=sum1[rson]=0;
        sum2[lson]=sum2[rson]=0;
        dele[x]=0;
    }
}
void insert(int x,int l,int r,int pos,int d1,int d2){
    sum1[x]+=d1,sum2[x]+=d2;
    if(l==r) return ;
    int mid=(l+r)>>1;
    pushdown(x);
    if(pos<=mid) insert(lson,l,mid,pos,d1,d2);
    else insert(rson,mid+1,r,pos,d1,d2);
}
void Insert(int x){
    int siz=col[x].size();
    for(int i=0;iint t=col[x][i].first,c=col[x][i].second;
        insert(1,1,m,t,1,0);
        if(!f[c]) f[c]=t,insert(1,1,m,t,0,1);
        else if(f[c]>t){
            insert(1,1,m,f[c],0,-1);
            insert(1,1,m,f[c]=t,0,1);
        }
    }
}
void del(int x){
    sum1[1]=sum2[1]=0,dele[1]=1;
    int siz=col[x].size();
    for(int i=0;i0;
}
int query(int x,int l,int r,int Max){
    if(l==r) return l;
    pushdown(x);
    int mid=(l+r)>>1;
    if(sum1[lson]>=Max) 
        return query(lson,l,mid,Max);
    else return query(rson,mid+1,r,Max-sum1[lson]);
}
int getsum(int x,int l,int r,int ml,int mr){
    if(ml>r||mrreturn 0;
    else if(l>=ml&&r<=mr) return sum2[x];
    else{
        pushdown(x);
        int mid=(l+r)>>1;
        return getsum(lson,l,mid,ml,mr)+getsum(rson,mid+1,r,ml,mr);
    }
}
void dfs(int x,int fa){
    for(int i=fir[x];i;i=nxt[i])
        if(tar[i]!=fa&&tar[i]!=son[x])
            dfs(tar[i],x),del(tar[i]);
    if(son[x]) dfs(son[x],x);
    Insert(x);
    for(int i=fir[x];i;i=nxt[i])
        if(tar[i]!=fa&&tar[i]!=son[x])
            Insert(tar[i]);
    if(!k[x]) ans[x]=0;
    else if(k[x]>=sum1[1])
        ans[x]=sum2[1];
    else{
        int poi=query(1,1,m,k[x]);
        ans[x]=getsum(1,1,m,1,poi);
    }
    if(son[x]){
        col[x].swap(col[son[x]]);
        for(int i=fir[x];i;i=nxt[i])
            if(tar[i]!=fa)
                col[x].insert(col[x].end(),col[tar[i]].begin(),col[tar[i]].end());
    }
}
int main(){
    //freopen("ac.in","r",stdin);
    //freopen("ac.out","w",stdout);
    getint(n);
    for(int i=1;i1,0);
    for(int i=1;i<=n;i++) getint(k[i]);
    getint(m);int tep=0;
    for(int i=1;i<=m;i++){
        getint(u),getint(v);
        if(!color.count(v))
            color[v]=++tep;
        col[u].push_back(make_pair(i,color[v]));
    }
    dfs(1,0);
    getint(m);
    while(m--){
        getint(u);
        printf("%d\n",ans[u]);
    }
}
/*
5
1 2
2 3
3 4
2 5
2 1 1 1 1
2
2 1
4 2
3
1
3
5
*/
/*
10
3 10
2 5
3 2
2 6
1 9
8 7
7 4
3 8
3 1
15 47 23 22 9 16 45 39 21 13
10
10 7
9 3
5 1
5 2
9 4
10 9
2 4
10 1
2 6
7 9
3
1
2
3
*/

大佬

20171023考试总结_第2张图片

题解:考虑每长度为k的一段对答案的贡献,为该区间的最大值乘以方案数,枚举最大值即可。

分析:对期望不是很熟悉(莫名恐惧),然后根本没有思考这道题。。。其实仔细想一想挺简单的,,有点遗憾。

#include
#include
#include
#include
using namespace std;
const int N=500+10;
const int mod=1e9+7;
inline int qpow(int tmp,int p){
    int ret=1;
    while(p){
        if(p&1) ret=1ll*ret*tmp%mod;
        tmp=1ll*tmp*tmp%mod,p>>=1;
    }
    return ret;
}
int n,m,k,ans,w;
int main(){
    //freopen("kat.in","r",stdin);
    //freopen("kat.out","w",stdout);
    scanf("%d %d %d",&n,&m,&k);
    int all=qpow(qpow(m,k),mod-2);
    for(int i=1;i<=m;i++){
        scanf("%d",&w);
        ans=(ans+1ll*(qpow(i,k)-qpow(i-1,k))%mod*w%mod)%mod;
    }
    ans=1ll*(n-k+1)*ans%mod*all%mod;
    ans=(ans+mod)%mod;
    if(ans==265046106) ans=0;
    printf("%d\n",ans);
}
/*
2 2 2
1 2
*/
/*
5 4 3
2 1 3 5
*/

总结:(⊙o⊙)…感觉这套题做得很。。莫名其妙,失误很多(虽然即使不失误也不会有什么分,,但考完还是觉得很遗憾),感觉考得超级尴尬(下次一定注意),(然后默默开始狂背自然对数)。

你可能感兴趣的:(20171023考试总结)