牛客小白月賽22 【無I】

題目鏈接:https://ac.nowcoder.com/acm/contest/4462
最近沉迷於寫Minecraft的mod,好久沒寫題了,拿了結束好幾天的這場練練手,好自閉哇~ AB都沒寫出來 只寫了D - H 和J 共六題…狀態極其不好
截至目前,除了沒有I題工具人的題解,本套其他題均有~


我的程序頭

爲了節省篇幅(代碼複用嘛)233

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rr(x,y) read(x);read(y)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
#define pb(x) push_back(x)
#define sss(str) scanf("%s",str+1)
#define ssf(x) scanf("%lf",&x)
#define all(x) x.begin(),x.end()
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef double dd;
typedef pair<LL,LL> pt;
const int N=1e5+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=1e9+7;
const int sz=18;
const double eps=1e-10;
const double pi=acos(-1);
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}

A 操作序列

這題我比賽時想的好複雜,各種數據結構,都沒寫出了。看題解才知道 就是個簡單的STL運用…
把不爲0的全部用map記錄下來(map自動離散化了,懶人必備
①:增加,先二分找到map的[t30,t+30][t-30,t+30]的左右區間 然後有的話說明 不用加,沒有的話就加唄
②:如果map不爲空,那map的第一個元素去掉就行了
③:找得到輸出找到的,找不到輸出0
完事了…

//***********************
LL n;
map<int,int> m;
//***********************
int main()
{
    r(n);
    FOR(i,1,n){
        int a;
        scanf("%d",&a);
        char c=getchar();
        if(a==-1){
            if(m.begin()==m.end()){
                cout<<"skipped\n";
            }
            else{
                cout<<(m.begin())->second<<endl;
                m.erase(m.begin());
            }
        }
        else if(c=='\n'){
            if(m.count(a)) cout<<m[a]<<endl;
            else cout<<0<<endl;
        }
        else if(c==' '){
            int b; r(b);
            bool flag=1;
            map<int,int>::iterator it;
            for(it=m.lower_bound(a-30);it!=m.upper_bound(a+30);it++){
                flag=0;
                break;
            }
            if(flag){
                if(m.count(a)) m[a]+=b;
                else m[a]=b;
            }
        }
    }
    return 0;
}


B 樹上子鏈

我們從一個點出發,記錄它往下dfs的最長鏈和次長鏈,最長鏈+次長鏈+它本身就是包含它的最長鏈,如果不包含就往上返回嘛(返回這個節點+最長鏈,注意沒有次長鏈)

//***********************
LL n,m;
struct edge
{
    int to,next;
}e[N<<1];
int head[N],f[N];
int cnt;
LL ans;
//***********************
void add_edge(int a,int b)
{
    e[++cnt].to=b;
    e[cnt].next=head[a];
    head[a]=cnt;
}
LL dfs(int x,int fa)
{
    //cout<<x<<endl;
    LL max1=0,max2=0;
    for(int i=head[x];i;i=e[i].next){
        int y=e[i].to;
        if(y!=fa){
            LL tmp=dfs(y,x);
            if(tmp>max1){
                max2=max1;
                max1=tmp;
            }
            else if(tmp>max2) max2=tmp;

        }
    }
    ans=max(ans,max1+max2+f[x]);
    return max1+f[x];
}
int main()
{
    r(n);
    FOR(i,1,n) r(f[i]);
    cnt=0;
    FOR(i,1,n-1){
        int a,b;
        rr(a,b);
        add_edge(a,b);
        add_edge(b,a);
    }
    ans=-6e18;
    dfs(1,-1);
    cout<<ans<<endl;
    return 0;
}


C 交換遊戲

我貌似沒有仔細想這題,題目都看錯了,我以爲有N個孔(1e5),雖然不看錯可能也不會
每個孔就2種狀態,記爲0和1,,12個孔就212=4096種,我們記憶化搜索記錄前一個狀態的值的話 那它這麼多詢問也是O(1)解決了 然後找到轉移的共性 3個相鄰的孔 中間爲1,兩邊異或爲1 轉移即與7異或(111)

//***********************
LL n,m;
char s[20];
int f[N];
//***********************
int dfs(int x)
{
    if(f[x]|| !x) return f[x];
    int cnt=0;
    FOR(i,0,11){
        if((1<<i)&x) cnt++;
    }
    FOR(i,0,9){
        if(((x>>i+1)&1)&&((x>>i+2)&1)^((x>>i)&1)){
            cnt=min(cnt,dfs(x^(7<<i)));
        }
    }
    return f[x]=cnt;
}
int main()
{
    r(n);
    f[0]=0;
    FOR(i,1,n){
        scanf("%s",s);
        int res=0;
        FOR(i,0,11){
            if(s[i]=='o') res+=(1<<i);
        }
        cout<<dfs(res)<<endl;
    }
    return 0;
}


D 收集紙片

好像是那啥狀壓dp解決TSP問題?半年前寫的 不太記得了,但是瞎寫就AC了~~(也不知道有沒有漏洞,我是dp蒟蒻)~~
一看到10個紙片就想到了狀壓,就是轉移的問題,我們令dp[ i ][ j ]爲 現在狀態爲i 端點爲j的最小距離 ,怎麼理解狀態i呢?就是把它看成二進制數,有幾個1,那個1位置對應的點就是已經走到了的

//***********************
int n,m;
char str[N];
int dp[1<<sz][sz];
int a[sz],b[sz];
int dis[sz][sz];
//***********************
int main()
{
    int t;r(t);
    while(t--){
        r(n); r(m);
        int st,se,k;
        rrr(st,se,k);
        FOR(i,1,k){
            rr(a[i],b[i]);
        }
        FOR(i,1,k){
            FOR(j,1,k){
                dis[i][j]=abs(a[i]-a[j])+abs(b[i]-b[j]);
            }
        }
        memset(dp,127/3,sizeof dp);
        FOR(i,1,k){
            dp[1<<i-1][i]=abs(a[i]-st)+abs(b[i]-se);
        }
        FOR(i,1,(1<<k)-1){
            FOR(j,1,k){
                int t=1<<j-1;
                if(t&i){
                    FOR(l,1,k){
                        if(l==j||((1<<l-1)&i)==0) continue;
                        dp[i][j]=min(dp[i][j],dp[i^t][l]+dis[j][l]);
                    }
                }
            }
        }
        int ans=INF;
        FOR(i,1,k){
            ans=min(ans,dp[(1<<k)-1][i]+abs(a[i]-st)+abs(b[i]-se));
        }
        cout<<"The shortest path has length "<<ans<<endl;
    }
    return 0;
}


E 方塊塗色

水題

//***********************
int n,m;
char str[N];
//***********************
int main()
{
    int a,b;
    while(~scanf("%d%d%d%d",&n,&m,&a,&b)){
        cout<<1ll*(n-a)*(m-b)<<endl;
    }
    return 0;
}


F 累乘數字

水題

//***********************
LL n,m;
//***********************
int main()
{
    while(~scanf("%d%d",&n,&m)){
    cout<<n;
    FOR(i,1,m) cout<<"00";
    cout<<endl;
}
    return 0;
}


G 倉庫選址

這題有點意思,我的思路是考慮點之間的轉移
假如我們現在選定了點(1,1)爲倉庫,那麼求出以這個點爲倉庫的答案是1e4,然後假如我們現在改成點(1,2)那這個答案會怎麼改變? 答案加上1那一列的數字和,然後減去2到m列的數字和 這個是不是可以通過記錄前綴和O(1)搞定? 同理(2,1)也是很好解決的~

//***********************
int n,m;
int f[M][M];
int sum[M][M];
//***********************

int main()
{
    int t;
    r(t);
    while(t--){
        rr(n,m);
        swap(n,m);
        FOR(i,1,n){
            FOR(j,1,m){
                r(f[i][j]);
                sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+f[i][j];
            }
        }
        int res=0;
        FOR(i,1,n){
            FOR(j,1,m){
                res+=(i+j-2)*f[i][j];
            }
        }
//        FOR(i,1,n){
//            FOR(j,1,m) cout<<sum[i][j]<<' ';
//            cout<<endl;
//        }
        int ans=res,now=res;
        FOR(i,1,n){
            int tmp=now;
            ans=min(ans,tmp);
            FOR(j,1,m){
                tmp+=sum[n][j]-(sum[n][m]-sum[n][j]);
                ans=min(ans,tmp);
            }
            now+=sum[i][m]-(sum[n][m]-sum[i][m]);
        }
        cout<<ans<<endl;
    }
    return 0;
}


H 貨物種類

我的做法是把相同的貨物的操作能合併的先合併,然後就不會出現重複給相同貨物的情況了。最後差分~

//***********************
int n,m;
struct node
{
    int l,r,v;
    bool operator<(node a)
    {
        if(v==a.v&&l==a.l) return r<a.r;
        if(v==a.v) return l<a.l;
        return v<a.v;
    }
    node(){};
    node(int ll,int rr,int vv){
        l=ll; r=rr; v=vv;
    }
}f[N],g[N];
int sum[N];
//***********************
int main()
{
    rr(n,m);
    FOR(i,1,m){
        rrr(f[i].l,f[i].r,f[i].v);
    }
    sort(f+1,f+m+1);
    int cnt=0,l=f[1].l,r=f[1].r;
    FOR(i,2,m+1){
        if(f[i].v==f[i-1].v){
            if(f[i].l<=r){
                r=max(r,f[i].r);
            }
            else{
                sum[l]++; sum[r+1]--;
                l=f[i].l; r=f[i].r;
            }
        }
        else{
            sum[l]++; sum[r+1]--;
            l=f[i].l; r=f[i].r;
        }
    }
    int ans=0,maxx=0,now=0;
    FOR(i,1,n){
        now+=sum[i];
        if(now>maxx){
            maxx=now;
            ans=i;
        }
       // cout<<now<<endl;
    }
    cout<<ans<<endl;
    return 0;
}


I 工具人


J 計算A+B

我開的第一題,看到A+B就覺得好寫。然後被搞心態了…
大模擬,不用多解釋吧…

//***********************
LL n,m;
char str[N];
int s1[N],s2[N];
//***********************
bool check(int l,int r)
{
    //cout<<l<<' '<<r<<endl;
    if(l>r) return 0;
    if(str[l]=='0'&&l!=r){
        return 0;
    }
    return 1;
}
int main()
{
    int t;
    r(t);
    while(t--){
        scanf("%s",str+1);
        int len=strlen(str+1);
        int mid=0,num=0;
        bool flag=1;
        FOR(i,1,len){
            if(str[i]=='+'){
                num++;
                mid=i;
            }
            if(str[i]!='+'&&str[i]<'0'&&str[i]>'9'){
                flag=0;
                break;
            }
        }
        if(num!=1||!flag){
            cout<<"skipped\n";
            continue;
        }
        if(check(1,mid-1)==0||check(mid+1,len)==0){
            cout<<"skipped\n";
            continue;
        }
        memset(s1,0,sizeof s1);
        memset(s2,0,sizeof s2);
        for(int i=mid-1;i>=1;i--) s1[mid-i]=str[i]-'0';
        for(int i=len;i>=mid+1;i--) s2[len-i+1]=str[i]-'0';
        int n=mid-1,m=len-mid;
        FOR(i,1,max(n,m)){
            s1[i]+=s2[i];
            int pos=i;
            while(s1[pos]>=10){
                s1[pos+1]++;
                s1[pos]-=10;
                pos++;
            }
        }
        int lst=0;
        for(int i=1e4+50;i>=1;i--){
            if(s1[i]!=0){
                lst=i; break;
            }
        }
        if(lst==0) cout<<0;
        for(int i=lst;i>=1;i--) cout<<s1[i];
        cout<<endl;
    }
    return 0;
}


end~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章