10.25~10.30任務題

三道11年noip。

vijos1738,1740,1741

1738

地址:https://vijos.org/p/1738

做法:做法:沒有做法,就是暴力大法師,一道代碼題,打打下落、消除這些基本操作。數組從0開始寫比1好寫,真是神奇。

代碼如下:

#include <bits/stdc++.h>
#define M 30
using namespace std;
int n,m,i,j,t,k,y,tp,showski;
int a[M][M],cnt[M],f[M][M],ans[M][M],mo[3]={0,1,-1};
inline void ps(int aa[M][M],int bb[M][M],int cc[],int dd[]){
    for(int i=0;i<5;i++)
        for(int j=0;j<7;j++) aa[i][j]=bb[i][j];
    for(i=1;i<=t;i++) cc[i]=dd[i];
}
inline int ok(){
    int tt=0;for(int i=1;i<=t;i++)
        if(cnt[i]) if(!tt||tt>cnt[i])
            tt=cnt[i];return tt;
}
inline void fl(int x){
    for(int i=0,j;i<7;i++)
        if(a[x][i]==0){
            for(j=i+1;j<7&&a[x][j]==0;j++);
            if(j==7) return;
            else a[x][i]=a[x][j],a[x][j]=0;
        }
}
inline int C(){
    int ff=0;for(int i=0;i<5;i++)
        for(int j=0;j<7;j++){
            if(!a[i][j]) continue;
            if(i<3&&a[i][j]==a[i+1][j]&&a[i][j]==a[i+2][j])
                f[i][j]=f[i+1][j]=f[i+2][j]=1;
            if(j<5&&a[i][j]==a[i][j+1]&&a[i][j]==a[i][j+2])
                f[i][j]=f[i][j+1]=f[i][j+2]=1;
        }for(i=0;i<5;i++) for(j=0;a[i][j]&&j<7;j++)
            if(f[i][j]) ff=1,cnt[a[i][j]]--,a[i][j]=f[i][j]=0;
    for(i=0;i<5;i++) fl(i);return ff;
}
inline void dfs(int x){
    int b[M][M],c[M];ps(b,a,c,cnt);
    for(int i=0;i<5;i++) for(int j=0;a[i][j]&&j<7;j++)
        for(int k=1;k<=2;k++)
            if(i+mo[k]>=0&&i+mo[k]<5){
                if((mo[k]==-1&&a[i-1][j])||a[i][j]==a[i+mo[k]][j]) continue;
                ans[x][1]=i;ans[x][2]=j;ans[x][3]=mo[k];
                swap(a[i][j],a[i+mo[k]][j]);
                for(fl(i),fl(i+mo[k]);C(););tp=ok();
                if(x==n) if(tp==0)
                for(i=showski=1;i<=n;i++)
                    printf("%d %d %d\n",ans[i][1],ans[i][2],ans[i][3]);
                if(showski==1) return;
                if(x!=n&&tp>2) dfs(x+1);
                ps(a,b,cnt,c);
             }
}
int main(){
    for(scanf("%d",&n),i=0;i<5;i++)
        for(j=0;j<=7;j++){ 
            scanf("%d",&y);if(y==0) break;
            a[i][j]=y;t=t>y?t:y;cnt[y]++;
        }dfs(1);if(!showski) printf("-1\n");return 0;
}

1740

地址:https://vijos.org/p/1740

做法:如果你手算幾個(或者你比較聰明的話),你應該就可以看出來檢驗值Yi是單調的,所以一眼二分。1s的時間,nlogn就過了,不寫樹狀數組了。

代碼如下:

#include <bits/stdc++.h>
#define M 200010
#define ll long long
using namespace std;
ll n,m,s,i,j,x,y,a,b,t,ans;
ll v[M],w[M],l[M],r[M],sum[M],cnt[M];
inline ll cal(ll x){
    for(t=cnt[0]=sum[0]=0,i=1;i<=n;i++){
        sum[i]=sum[i-1];cnt[i]=cnt[i-1];
        if(w[i]>=x) cnt[i]++,sum[i]+=v[i];
    }for(i=0;i<m;i++)
        t+=(cnt[r[i]]-cnt[l[i]-1])*(sum[r[i]]-sum[l[i]-1]);
    return t;
}
int main(){
    for(scanf("%lld%lld%lld",&n,&m,&s),i=1;i<=n;i++){
        scanf("%lld%lld",&w[i],&v[i]);
        if(a>w[i]) a=w[i];
        if(b<w[i]) b=w[i];
    }for(i=0;i<m;i++)
        scanf("%lld%lld",&l[i],&r[i]);
    while(b-a>1){
        ll mid=a+b>>1;
        if(cal(mid)>s) a=mid;else b=mid;
    }ans=min(abs(cal(a)-s),abs(cal(b)-s));
    printf("%lld\n",ans);return 0;
}

1741

地址:https://vijos.org/p/1741

做法:想到了一個極其暴力的貪心,看到vijos標籤上寫樹形動規只覺得汗顏。只要存下車開到每個站點的時間和該站點最晚到的乘客的時間。每次尋找一段路,使得坐車的人最多,並且滿足車比下一個站點最晚到的乘客到的晚,然後使勁用加速器。如果加速器太多了,直到車和最晚到的乘客同時到達下一個站點即可,然後尋找下一個合法的區間。最後掃一遍統計答案就好了。

#include <bits/stdc++.h>
#define M 100010
using namespace std;
int showski=1,n,m,k,i,j,mx,xx,ans; 
int t[M],a[M],b[M],ar[M],la[M],d[M],tmp[M],sum[M];
int main(){
    for(scanf("%d%d%d",&n,&m,&k),i=1;i<n;i++) scanf("%d",&d[i]);
    for(i=1;i<=m;i++){
        scanf("%d%d%d",&t[i],&a[i],&b[i]);
        sum[b[i]]++;
        if(t[i]>la[a[i]]) la[a[i]]=t[i];
    }for(i=2;i<=n;i++) sum[i]+=sum[i-1];
    while(showski){
        for(ar[1]=0,i=2;i<=n;i++) ar[i]=max(ar[i-1],la[i-1])+d[i-1];
        for(tmp[n]=n,i=n-1;i>=1;i--){
            tmp[i]=tmp[i+1];
            if(ar[i+1]<=la[i+1]) tmp[i]=i+1; 
        }for(mx=1;!d[mx]&&mx<=n-1;) mx++;
        if(mx==n||k==0) break;
        for(i=mx+1;i<n;i++)
            if(d[i]&&sum[tmp[mx]]-sum[mx]<sum[tmp[i]]-sum[i]) mx=i;
        if(sum[tmp[mx]]-sum[mx]==0) break;
        for(xx=M-5,i=mx+1;i<=tmp[mx]-1;i++)
            xx=min(xx,ar[i]-la[i]);
        xx=min(xx,k);xx=min(xx,d[mx]);k-=xx;d[mx]-=xx;
        //cout<<k<<" "<<xx<<endl;system("pause");
    }for(i=1;i<=m;i++) ans+=abs(ar[b[i]]-t[i]);
    printf("%d\n",ans);return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章