2017.11.05离线赛总结

game ——3808

思路:暴力dfs,然而只有30分,正解也显然是数学归纳,也可以按照解答树展开,不难发现 ans[i]=ans[i1]2+num[i]ij=0num[j]2j

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath> 
#include<cstdlib>
#include<algorithm>
#include<vector>
using namespace std;

#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--)
#define LL long long
#define db double
#define INF 0x3f3f3f3f
#define inf 0x7fffffff
#define Sz(a) sizeof(a)
#define mcl(a,b) memset(a,b,Sz(a))  
#define pb push_back

#define P 1000000007
#define N 200005

int n;
LL A[N];
LL ans;
struct p30{
    void dfs(int x,LL sum,LL l,LL r){
        if(x==n+1){
            (ans+=sum)%=P;
            return;
        }
        dfs(x+1,(sum+A[x]*l%P)%P,A[x],r);
        dfs(x+1,(sum+A[x]*r%P)%P,l,A[x]);
    }
    void solve(){
        dfs(1,0,A[0],A[0]);
        cout<<ans<<endl;
    }
}p30;

struct p100{
    void solve(){
        LL Pow=1,sum=A[0]<<1;
        REP(i,1,n){
            (ans=ans*2%P+A[i]*sum%P)%=P;
            (Pow<<=1)%=P;
            (sum+=Pow*A[i]%P)%=P;
        }
        cout<<ans<<endl; 
    }
}p100;
int main(){
//  freopen("game.in","r",stdin);
//  freopen("game.out","w",stdout);
    cin>>n;
    REP(i,0,n)scanf("%lld",&A[i]);
    if(n<20)p30.solve(); 
    else p100.solve();
    return 0;
} 

cable —— 3809

思路:暴力最小生成树40分;蒟蒻原以为正解是贪心,然而现实总是残酷的,此题显然是dp(大佬说的…)。
看完题解后,感觉dp也是最简单的写法了,且因为村庄时两列的,那么重点是关注两列之间的建边的比较,那么也有点感到定义是与n,m有关的—— dp[i][j][2]
dp[i][j][1]=min(dp[i1][j][1]+min(Dx,Dy),dp[i1][j][0]+Dx+Dy);
dp[i][j][0]=min(dp[i1][j][1],dp[i1][j][0]+Dx)(Dx=A[i]A[i1]orB[i]B[i1],Dy=dis(i,j)).

不难发现 i ,j 都能滚动,且O(n+m)。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath> 
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<vector>
using namespace std;

#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--)
#define LL long long
#define db double
#define INF 0x3f3f3f3f
#define inf 0x7fffffff
#define Sz(a) sizeof(a)
#define mcl(a,b) memset(a,b,Sz(a))
#define pb push_back

#define N 1000005

void Rd(int &x){
    x=0;char c;
    while(c=getchar(),c<48);
    do x=(x<<1)+(x<<3)+(c^48);
    while(c=getchar(),c>47);
}

int n,m,x1,x2;
int A[N],B[N];
LL dx;


struct p40{
    struct node{
        int from,to;
        db cost;
        bool operator<(const node &a)const{
            return cost<a.cost;
        }
    }es[N<<1];
    int fa[N<<1];
    int cnt;
    db calc(int y1,int y2){
        return 1.0*sqrt(dx+1.0*(y2-y1)*(y2-y1));
    }
    void Init(){
        REP(i,2,n)es[++cnt]=(node){i-1,i,(db)(A[i]-A[i-1])};
        REP(i,2,m)es[++cnt]=(node){i+n-1,i+n,(db)(B[i]-B[i-1])};
        REP(i,1,m)REP(j,1,n)es[++cnt]=(node){i+n,j,(db)calc(A[j],B[i])};
    }
    int Find(int x){return fa[x]==x?x:fa[x]=Find(fa[x]);}

    void solve(){
        db ans=0;
        Init();
        sort(es+1,es+1+cnt);
        REP(i,1,n+m)fa[i]=i;
        REP(i,1,cnt){
            int x=es[i].from,y=es[i].to;
            int fx=Find(x),fy=Find(y);
            if(fx!=fy){
                fa[fy]=fx;
                ans+=es[i].cost;
            }
        }
        printf("%.2lf\n",ans);
    }
}p40;


db dp[N][2][2];
struct p100{
    db Calc(int i,int j) {
        return sqrt(dx+1LL*(A[i]-B[j])*(A[i]-B[j]));
    }
    void solve(){
        dp[1][1][1]=Calc(1,1);
        int cur=1;
        REP(i,1,n){
            if(i!=1){
                db Dx=Calc(i,cur),Dy=A[i]-A[i-1];
                int now=cur&1;
                dp[i][now][1]=min(dp[i-1][now][1]+min(Dx,Dy),dp[i-1][now][0]+Dx+Dy);
                dp[i][now][0]=min(dp[i-1][now][1],dp[i-1][now][0]+Dy);
            }
            while((A[i]>=B[cur] || i>=n) && cur<m){
                cur++;
                db Dx=Calc(i,cur),Dy=B[cur]-B[cur-1];
                int now=cur&1;
                dp[i][now][1]=min(dp[i][now^1][1]+min(Dx,Dy),dp[i][now^1][0]+Dx+Dy);
                dp[i][now][0]=min(dp[i][now^1][1],dp[i][now^1][0]+Dy);
            }
        }
        printf("%.2lf\n",dp[n][m&1][1]);
    }
}p100;
struct pAC{
    db dp[2][2][2];
    int cur1,cur2;
    db calc(int i,int j){
        return sqrt(dx+1LL*(A[i]-B[j])*(A[i]-B[j]));
    }
    void work_i(int i,int j){
        db Dx=calc(i,j),Dy=A[i]-A[i-1];
        dp[!cur1][cur2][0]=min(dp[cur1][cur2][1],dp[cur1][cur2][0]+Dy);
        dp[!cur1][cur2][1]=min(dp[cur1][cur2][1]+min(Dx,Dy),dp[cur1][cur2][0]+Dx+Dy);
        cur1^=1;
    }
    void work_j(int i,int j){
        db Dx=calc(i,j),Dy=B[j]-B[j-1];
        dp[cur1][!cur2][0]=min(dp[cur1][cur2][1],dp[cur1][cur2][0]+Dy);
        dp[cur1][!cur2][1]=min(dp[cur1][cur2][1]+min(Dx,Dy),dp[cur1][cur2][0]+Dx+Dy);
        cur2^=1;
    }
    void solve(){
        dp[cur1][cur2][0]=0;
        dp[cur1][cur2][1]=calc(1,1);
        int j=1;
        REP(i,1,n){
            if(i>1)work_i(i,j);
            while(j<m && (A[i]>=B[j] || i==n))work_j(i,++j);
        }
        printf("%.2lf\n",dp[cur1][cur2][1]);
    }
}pAC;
int main(){
//  freopen("cable.in","r",stdin);
//  freopen("cable.out","w",stdout);
//  printf("%d\n",(Sz(A)+Sz(B)+Sz(fa)+Sz(dy1)+Sz(dy1))/1024/1024);
    srand(time(NULL));
    int f=rand()%2;
    cin>>n>>m>>x1>>x2;
    dx=1LL*(x1-x2)*(x1-x2);
    REP(i,1,n)Rd(A[i]),A[i]+=A[i-1];
    REP(i,1,m)Rd(B[i]),B[i]+=B[i-1];
    if(n<=1000 && m<=1000)p40.solve();
    else if(f)p100.solve();
    else pAC.solve();
    return 0;
} 

seat ——3810

思路:此题暴力共计40分,然而m=1还是没推出来,十分遗憾…
60分可以状压dp,but这根本不会想到dp去…
定义和转移都是十分easy的…
dp[i][j] 表示 i 个人固定了位置后状态为 j ;
正解的复杂度也比较玄乎(数据略水)——dfs,m<=8,小的离谱,这告诉我们着突破点。
考虑 n<=10 的做法,其实我们只关注已经固定编号的人的位
置是否合法就行了。
那么我们就去 dfs 每个已经固定了编号的人。假设第 i 个人编号为 x ,需要坐到 y ,那么就需要坐在 xy1 之间的人都在 i <script type="math/tex" id="MathJax-Element-735">i</script> 之前选择位置,这里就可以组合数来计算。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath> 
#include<cstdlib>
#include<algorithm>
#include<vector>
using namespace std;

#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--)
#define LL long long
#define db double
#define INF 0x3f3f3f3f
#define inf 0x7fffffff
#define Sz(a) sizeof(a)
#define mcl(a,b) memset(a,b,Sz(a))  
#define mcp(a,b) memcpy(a,b,Sz(b))
#define pb push_back

#define N 35

int n,m,P;
LL ans;
int D[N],A[N];
bool mark[N];
LL C[N][N],fac[N];

struct node{
    int x,pos;
    bool operator<(const node &a)const{
        return x<a.x;
    }
}B[N];

void Init(){
    C[0][0]=1;
    REP(i,1,N-5){
        C[i][0]=1;
        REP(j,1,i)C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
    }
    fac[0]=1;
    REP(i,1,N-5)fac[i]=fac[i-1]*i%P;
}

struct P30{
    void dfs(int x){
        if(x>n){
            ans++;
            return;
        }
        if(!A[x])REP(i,1,n){
            if(mark[i])continue;
            D[x]=i;
            mark[i]=1;
            dfs(x+1);
            mark[i]=0;
        }
        else {
            REP(i,A[x],n){
                if(mark[i])continue;
                D[x]=i;
                mark[i]=1;
                dfs(x+1);
                mark[i]=0;
                break;
            }
        }
    }
    void solve(){
        REP(i,1,m){
            int x,pos;
            scanf("%d%d",&x,&pos);
            A[x]=pos;
        }
        dfs(1);
        printf("%lld\n",ans%P);
    }
}p30;

struct p0{
    void solve(){
        printf("%lld\n",fac[n]);
    }
}p0;

struct p1{
    void solve(){
        REP(i,1,m){
            int x,pos;
            scanf("%d%d",&x,&pos);
            A[x]=pos;
        }
        int u=0;
        REP(i,1,n)if(A[i])u=i;
        ans=fac[n-1];
        REP(i,1,n){
            if(A[u]+i>n||u-1<i)break;
            ans+=C[u-1][i]*fac[i]%P*fac[n-i-1]%P;
            ans%=P;
        }
        printf("%lld\n",ans%P);
    }
}p1;

struct p60{
    #define M 20
    LL dp[M][1<<M];
    void solve(){
        REP(i,1,m){
            int x,pos;
            scanf("%d%d",&x,&pos);
            A[x]=pos-1;
            mark[x]=1;
        }
        mcl(dp,-1);
        dp[0][0]=1;
        REP(k,1,n){
            REP(i,0,(1<<n)-1){
                if(dp[k-1][i]==-1)continue;
                REP(j,A[k],n-1){
                    if(i&(1<<j))continue;
                    if(dp[k][i|(1<<j)]==-1)dp[k][i|(1<<j)]=0;
                    (dp[k][i|(1<<j)]+=dp[k-1][i])%=P;
                    if(mark[k])break;
                }
            }
        }
        printf("%lld\n",dp[n][(1<<n)-1]==-1?0:dp[n][(1<<n)-1]);
    }
}p60;

struct p100{
    void dfs(int x,int res,LL sum){
        if(x==m+1){
            res+=n-B[m].x;
            ans+=fac[res]*sum%P,ans%=P;
            return;
        }
        res+=B[x].x-B[x-1].x-1;
        int cnt=0;
        bool tmp[N];
        mcp(tmp,mark);
        REP(i,B[x].pos,n){
            if(mark[i])continue;
            if(cnt>res)break;
            mark[i]=1;
            dfs(x+1,res-cnt,sum*C[res][cnt]%P*fac[cnt]%P);
            cnt++;
        }
        mcp(mark,tmp);
    }

    void solve(){
        REP(i,1,m)scanf("%d%d",&B[i].x,&B[i].pos);
        sort(B+1,B+1+m);
        dfs(1,0,1); 
        cout<<ans<<endl;
    }
}p100;

int main(){
//  freopen("seat.in","r",stdin);
//  freopen("seat.out","w",stdout);
    scanf("%d%d%d",&n,&m,&P);
    Init();
    if(m==0)p0.solve();
    else if(m==1)p1.solve();
    else if(n<10)p30.solve();
    else if(n<20)p60.solve();
    else p100.solve();
    return 0;
}

小结:今天的整体难度相比昨天大幅提升(对于蒟蒻来说吧),然而noip是你琢磨不透的,也有可能今年的三道题目难度顺序不再递增,很有可能不按照一般套路出牌了。 所以一定要放好心态,写好note再敲。
其也是导致了今天第1题爆0(最后急了,文件名没开…),第3题的暴力敲的很乱很慢很杂。
这也时刻体现自我的代码功底还是格外的薄弱,对数据范围的敏感度还是不够(如 m<=20 ——刚好状压 , Ai<=1e9 —— 开LL)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值