2017-11-5离线赛总结(NOIP七连测第三场)

来源:互联网 发布:网络图标不见了 编辑:程序博客网 时间:2024/05/16 14:27

失分小结:
估分:100+80+40=220
实际分数:100+10+35=145
和估分相差甚远,主要是由于第一题的难度提升
又在第一题上卡了太久,导致第二题随便打了个暴力后又去水第三题
虽然主体顺序是没有错的,但是心态就不一样了,想着多水点分,又感觉时间来不及,虽然最后第二题想到了最小生成树,但又因为取边取错爆炸,暴力(dp)写错
题解:
Task 1:
第一题如果直接考虑两个数之间的关系的话,还是较为容易的,方案一共就只有n2种,我们也只用枚举这么多,然后剩下的就用排列组合推就好了
tip:当无法方案数很多时,可以把方案拆开,对单独的一个小步骤进行分析,然后利用排列组合求解
Task 2:
第二题也较为玄学,直接使用最小生成树算法可以卡过去
dp的大体转移好想,但具体的实现就较为困难
可以推出一个点有几种连接方案:
1.与自己这一列的前一个点相连
2.与自己这一列的后一个点相连
3.与自己对面一列的一个点相连
对于第三种情况,可以贪心地实现
可以推算出若其他点已经相连,那么若要把这个点加入,
就要选择离自己最近的点,然这里又有一个特殊情况:
在我们对面的右边的点实际上并没有被加入到点集里,所以连接离自己最近的右边的点可能才是最优的(在最小生成树的算法中,就是要把这两个离自己最近的点加进去)
然后先不考虑空间优化,可以发现自己在对面的转移实际只有两种情况
而在自己这一列的转移只有一种情况,所以递推式就很容易出来了
代码实现:

#include<bits/stdc++.h>using namespace std;#define M 1000005#define du doubleint A[M],B[M];du dp[2][2][2];int x3,x1,x2;du dist(int x,int y){    return sqrt((long long)(A[x]-B[y])*(A[x]-B[y])+x3);}int main(){    int n,m;    scanf("%d%d%d%d",&n,&m,&x1,&x2);    x3=1ll*(x1-x2)*(x1-x2);    for(int i=1;i<=n;i++)scanf("%d",&A[i]),A[i]+=A[i-1];    for(int i=1;i<=m;i++)scanf("%d",&B[i]),B[i]+=B[i-1];    int j=1;    dp[1][1][1]=dist(1,1);    for(int i=1;i<=n;i++){//  1  i与j连通    0  i与j不连通         if(i>1){            dp[i&1][j&1][1]=min(dp[!(i&1)][j&1][1]+dist(i,j),            min(dp[!(i&1)][j&1][1]+A[i]-A[i-1],dp[!(i&1)][j&1][0]+A[i]-A[i-1]+dist(i,j)));            dp[i&1][j&1][0]=min(dp[!(i&1)][j&1][1],dp[!(i&1)][j&1][0]+A[i]-A[i-1]);        }           while(j<m&&(A[i]>=B[j]||i==n)){min(dp[i&1][!(j&1)][1]+B[j]-B[j-1],dp[i&1][!(j&1)][0]+B[j]-B[j-1]+dist(i,j)));            dp[i&1][j&1][0]=min(dp[i&1][!(j&1)][1],dp[i&1][!(j&1)][0]+B[j]-B[j-1]);        }    }    printf("%.2f\n",dp[n&1][m&1][1]);    return 0;}

Task 3:
感觉这次的第三题相比于第二题的正解来说更好搞一些
第三题就是dfs加玄学剪枝
如果切了m=1这一档就可以清楚地发现这个方案数是可以根据组合数递推的
这题给出的诡异的切分也很玄妙,前面五十分n小一些,后面50分m小一些
前50分可以直接状压,后50分就直接枚举m的位置,然后用组合数算就好了
代码实现(只有后50分)

#include<bits/stdc++.h>using namespace std;#define FOR(i,x,y) for(int i=(x);i<=(y);i++)#define ll long longint n,m,P;struct node{    int id,pos;    bool operator <(const node &s)const{return id<s.id;}}D[10];int C[35][35],fac[35];void init(){    FOR(i,0,30){cout<<666<<endl;        C[i][0]=C[i][i]=1;        FOR(j,1,i-1)C[i][j]=(C[i-1][j]+C[i-1][j-1])%P;    }    fac[0]=1;    FOR(i,1,30)fac[i]=1ll*fac[i-1]*i%P;}bool mark[35],used[35];int ans;void dfs(int x,int res,int tmp){    res+=D[x].pos-D[x-1].pos;    if(x>m){        tmp=1ll*tmp*fac[res]%P;        ans=(ans+tmp)%P;        return;    }    int sum=0;    for(int i=1;i<=n;i++)used[i]=mark[i];    for(int i=D[x].pos;i<=n;i++)if(!mark[i]){        sum++;        if(sum>res)break;        dfs(x+1,res-sum,tmp*fac[sum]%P*C[sum][res]%P);        mark[i]=1;    }    for(int i=1;i<=n;i++)mark[i]=used[i];}int main(){    init();    scanf("%d%d%d",&n,&m,&P);    FOR(i,1,m)scanf("%d%d",&D[i].id,&D[i].pos);    sort(D+1,D+1+m);    D[m+1].pos=n;    dfs(1,0,1);    printf("%d\n",ans);    return 0;}
原创粉丝点击