1. 程式人生 > >10月20日 訓練記錄 2018-2019 ICPC, NEERC, Southern Subregional Contest (Online Mirror, ACM-ICPC Rules, Team

10月20日 訓練記錄 2018-2019 ICPC, NEERC, Southern Subregional Contest (Online Mirror, ACM-ICPC Rules, Team

A題

題意:求數位總和為s且是d的倍數的最小值,若無解輸出-1

思路:s<=5000,d<=500說明狀態數<=s*d=5000*500,bfs搜尋

程式碼:

#include<bits/stdc++.h>
using namespace std;
struct node
{
    int mod;
    int sum;
    string num;
};
bool vis[5010][510];
int main()
{
    for ( int d,s ; scanf( "%d%d" , &d , &s )==2 ; )
    {
        memset ( vis , false , sizeof(vis) );
        queue<node>Q;
        node p,q;
        p.mod = 0;
        p.sum = 0;
        p.num = "";
        Q.push(p);
        vis[0][0] = true;
        bool ans = false;
        while ( !Q.empty() )
        {
            p = Q.front(); Q.pop();
            if  ( p.sum==s&&p.mod==0 )
            {
                ans = true;
                cout<<p.num<<endl;
            }
            for ( int i=0 ; i<=9 ; i++ )
            {
                q = p;
                q.mod = (q.mod*10+i)%d;
                q.sum = (q.sum+i);
                q.num += ('0'+i);
                if ( q.sum<=s&&!vis[q.sum][q.mod] )
                {
                    vis[q.sum][q.mod] = true;
                    Q.push(q);
                }
            }
        }
        if ( !ans ) cout<<"-1"<<endl;
    }
    return 0;
}

C題

題意:n,k,m,m個區間任務L,R表示執行時間,C表示需求機器數,P表示單臺機器價格,每個時間點最多使用K臺機器,求最小花費

思路:以花費排序維護兩個樹狀陣列,樹狀陣列A維護花費的數目,樹狀陣列B維護花費的總和,順序遍歷時間點,先二分滿足K臺數目以上的花費值,然後查詢該花費值的總和

程式碼:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 200010;
const int maxm = 400010;
typedef long long LL;
struct node
{
    int l,r,c,p;
}a[maxn];
int b[maxm],bb[maxn],n,k,m,mm;
vector< pair< int,pair<int,int> > >G[maxm];
LL bita[maxn],bitb[maxn],ans;
int lowbit( int x )
{
    return x&(-x);
}
void add( int u , LL a , LL b )
{
    for ( ; u<=mm ; u+=lowbit(u) )
    {
        bita[u] += a;
        bitb[u] += b;
    }
}
LL suma( int u )
{
    LL res = 0;
    for ( ; u>=1 ; u-=lowbit(u) )
        res += bita[u];
    return res;
}
LL sumb( int u )
{
    LL res = 0;
    for ( ; u>=1 ; u-=lowbit(u) )
        res += bitb[u];
    return res;
}
int main()
{
    scanf ( "%d%d" , &n , &k ); scanf ( "%d" , &n );
    for ( int i=0 ; i<n ; i++ )
    {
        scanf( "%d%d" , &a[i].l , &a[i].r );
        scanf( "%d%d" , &a[i].c , &a[i].p );
        a[i].r++;
        b[i*2+0] = a[i].l;
        b[i*2+1] = a[i].r;
        bb[i] = a[i].p;
    }
    sort ( b , b+n+n );
    m = unique( b , b+n+n )-b;
    /*
    for ( int i=0 ; i<m ; i++ )
        printf ( "%d " , b[i] );
    */
    //printf( "\n" );
    for ( int i=0 ; i<n ; i++ )
    {
        int tl = lower_bound( b , b+m , a[i].l )-b;
        int tr = lower_bound( b , b+m , a[i].r )-b;
        G[tl].push_back( make_pair(+1,make_pair(a[i].c,a[i].p)) );
        G[tr].push_back( make_pair(-1,make_pair(a[i].c,a[i].p)) );
    }
    for ( int i=0 ; i<m ; i++ )
        sort( G[i].begin() , G[i].end() );
    /*
    for ( int i=0 ; i<m ; i++ )
    {
        int sz = G[i].size();
        for ( int j=0 ; j<sz ; j++ )
            printf ( "%d %d %d %d\n" , i , G[i][j].first , G[i][j].second.first , G[i][j].second.second );
    }
    */
    sort ( bb , bb+n );
    mm = unique( bb , bb+n )-bb;
    /*
    printf ( "%d\n" , mm );
    for ( int i=0 ; i<mm ; i++ )
        printf ( "%d " , bb[i] );
    printf ( "\n" );
    */
    for ( int i=1 ; i<=mm ; i++ )
    {
        bita[i] = 0;
        bitb[i] = 0;
    }
    ans =  0;
    for ( int i=0 ; i<m ; i++ )
    {
        if ( i!=0 )
        {
            if ( suma(mm)<=k )
            {
                ans += 1LL*(b[i]-b[i-1])*sumb(mm);
                //printf ( "%d %I64d %I64d\n" , b[i] , suma(mm) , sumb(mm) );
            }
            else
            {
                int l=1,r=mm;
                while ( l<=r )
                {
                    int mid = (l+r)>>1;
                    if ( suma(mid)>=k ) r = mid-1;
                    else l = mid+1;
                }
                //printf ( "%d %d %d\n" , b[i] , l , bb[l-1] );
                //printf ( "%I64d\n" , suma(l) );
                //printf ( "%I64d\n" , suma(l-1) );
                ans += 1LL*(b[i]-b[i-1])*sumb(l-1);
                if ( suma(l)>=k ) ans += 1LL*(b[i]-b[i-1])*(k-suma(l-1))*bb[l-1];
            }
        }
        //printf ( "%I64d\n" , ans );
        int sz = G[i].size(),now;
        for ( now=0 ; now<sz&&G[i][now].first<0 ; now++ )
        {
            int cc = G[i][now].second.first;
            int pp = G[i][now].second.second;
            //printf ( "- %d %d %d\n" , i , cc , pp );
            int qq = lower_bound( bb , bb+mm , pp )-bb;
            //printf ( "%d %d %d %d\n" , i , cc , pp , qq );
            //printf ( "%d %d\n"  , b[i] , G[i][now].first );
            //printf ( "%d\n"  , qq+1 );
            add( qq+1 , -cc , -1LL*cc*pp );
        }
        for ( ; now<sz ; now++ )
        {
            int cc = G[i][now].second.first;
            int pp = G[i][now].second.second;
            int qq = lower_bound( bb , bb+mm , pp )-bb;
            //printf ( "+ %d %d %d\n" , i , cc , pp );
            add( qq+1 , cc , 1LL*cc*pp );
        }
    }
    printf ( "%I64d\n" , ans );
    return 0;
}

D題

題意:有n天每天有ai個貨物需要打包存倉,每個包裹最多存k個,貨物可以當天打包或者推遲一天,求最少使用包裹數

思路:每天最多保留ai個貨物,遍歷計算

程式碼:

#include<bits/stdc++.h>
using  namespace std;
typedef long long LL;

int main()
{
    int n,k;
    scanf( "%d%d" , &n , &k );
    LL ans = 0,need = 0;
    for ( int i=1 ; i<=n ; i++ )
    {
        int x;
        scanf( "%d" , &x );
        need += x;
        int low = ( need-x )/k;
        if ( (need-x)%k!=0 ) low++;
        ans += low;
        need -= 1LL*low*k;
        if ( need<0 ) need = 0;
    }
    ans += need/k;
    if ( need%k!=0 ) ans++;
    printf( "%I64d\n" , ans );
    return 0;
}

F題

題意:n個人有各自支援意向(11,10,01,00)和價值,從中選取一些人使得A的支持者大於等於總人數的一半B的支援這大於等於總人數的一半,求最大價值和

思路:貪心

程式碼:

#include<bits/stdc++.h>
using  namespace std;
int Abs( int a ){ return a<0?-a:a; }
vector<int>a[4];
int cal( char s[] )
{
    return (s[0]-'0')*2+(s[1]-'0');
}
int main()
{
    int n;
    scanf( "%d" , &n );
    char s[5]; int x;
    for ( int i=0 ; i<n ; i++ )
    {
        scanf ( "%s%d" , s , &x );
        a[cal(s)].push_back(x);
        //printf( "%d %d\n" , cal(s) , x );
    }
    for ( int i=1 ; i<4 ; i++ )
        sort( a[i].begin() , a[i].end() );
    int ans = 0;
    int sz3 = a[3].size();
    for ( int i=0 ; i<sz3 ; i++ )
        ans += a[3][i];
    //printf ( "%d\n" , ans );
    int sz1 = a[1].size();
    int sz2 = a[2].size();
    int dif = Abs(sz1-sz2);
    if ( sz1<sz2 )
    {
        for ( int i=0 ; i<sz1 ; i++ )
            ans += a[1][i]+a[2][i+dif];
        for ( int i=0 ; i<dif ; i++ )
            a[0].push_back(a[2][i]);
    }
    else
    {
        for ( int i=0 ; i<sz2 ; i++ )
            ans += a[1][i+dif]+a[2][i];
        for ( int i=0 ; i<dif ; i++ )
            a[0].push_back(a[1][i]);
    }
    //printf ( "%d\n" , ans );
    sort ( a[0].begin() , a[0].end() );
    int sz0 = a[0].size();
    for ( int i=sz0-1 ; i>=0&&sz3 ; i--,sz3-- )
        ans += a[0][i];
    printf( "%d\n" , ans );
    return 0;
}

H題

題意:有n個文字,q個詢問,每次詢問一個文字求它是幾個文字的子串

思路:先將文字和詢問讀入,對詢問建立AC自動機,對文字做詢問

程式碼:

#include<bits/stdc++.h>
using  namespace std;

char f[10010][10];
int ans1[50010],ans2[50010];
int change( char ch )
{
    if ( ch>='0'&&ch<='9' ) return ch-'0';
    if ( ch>='a'&&ch<='z' ) return ch-'a'+10;
    if ( ch=='.' ) return 36;
}
struct ACauto
{
    int next[400010][37],fail[400010],root,L;
    vector<int>end[400010];
    int newNode()
    {
        for( int i=0 ; i<37 ; i++ )
            next[L][i] = -1;
        end[L++].clear();
        return L-1;
    }
    void init()
    {
        L = 0; root = newNode();
    }
    void Insert( int id , char *s )
    {
        int len = strlen(s);
        int now = root;
        for( int i=0 ; i<len ; i++ )
        {
            int tmp = change(s[i]);
            if ( next[now][tmp]==-1 )
                next[now][tmp] = newNode();
            now = next[now][tmp];
        }
        end[now].push_back(id);
    }
    void Build()
    {
        queue<int>Q; fail[root] = root;
        for( int i=0 ; i<37 ; i++ )
        {
            if ( next[root][i]==-1 )
                next[root][i] = root;
            else
            {
                fail[next[root][i]] = root;
                Q.push(next[root][i]);
            }
        }
        while( !Q.empty() )
        {
            int now = Q.front(); Q.pop();
            for ( int i=0 ; i<37 ; i++ )
            {
                if ( next[now][i]==-1 )
                    next[now][i] = next[fail[now]][i];
                else
                {
                    fail[next[now][i]] = next[fail[now]][i];
                    Q.push(next[now][i]);
                }
            }
        }
    }
    void Query( int id , char *s )
    {
        int len = strlen(s);
        int now = root;
        for ( int i=0 ; i<len ; i++ )
        {
            int tmp = change(s[i]);
            now = next[now][tmp];
            int nxt = now;
            while ( nxt!=root )
            {
                if( end[nxt].size()&&ans2[end[nxt][0]]!=id )
                {
                    int sz = end[nxt].size();
                    for ( int j=0 ; j<sz ; j++ )
                    {
                        ans1[end[nxt][j]]++;
                        ans2[end[nxt][j]] = id;
                    }
                }
                nxt = fail[nxt];
            }
        }
    }
}AC;

int main()
{
    int n;
    scanf( "%d" , &n );
    for ( int i=0 ; i<n ; i++ )
        scanf ( "%s" , f[i] );
    int q;
    scanf( "%d" , &q );
    for ( int i=0 ; i<q ; i++ )
        ans1[i] = 0,ans2[i] = -1;
    char s[10];
    AC.init ();
    for ( int i=0 ; i<q ; i++ )
    {
        scanf ( "%s" , s );
        AC.Insert( i , s );
    }
    AC.Build();
    for ( int i=0 ; i<n ; i++ )
        AC.Query( i , f[i] );
    for ( int i=0 ; i<q ; i++ )
    {
        printf ( "%d " , ans1[i] );
        if ( ans2[i]==-1 ) printf( "-\n" );
        else printf ( "%s\n" , f[ans2[i]] );
    }
    return 0;
}

K題

題意:長度為n的陣列要求分成k段且每段的和相等,有解輸出各段長度無解輸出-1

思路:模擬一下一個K一個K向下找

程式碼:

#include<bits/stdc++.h>
using  namespace std;
typedef long long LL;

int a[100010],b[100010];

int main()
{
    int n,k;
    scanf( "%d%d" , &n , &k );
    a[0] = 0;
    for ( int i=1 ; i<=n ; i++ )
    {
        scanf ( "%d" , &a[i] );
        a[i] = a[i-1]+a[i];
    }
    bool ok = true;
    //printf ( "%d %d\n" , a[n] , k );
    if ( a[n]%k!=0 ) ok = false;
    else
    {
        b[0] = 0;
        int pos = 1,add = a[n]/k;
        for ( int i=1 ; i<=k ; i++ )
        {
            while ( a[pos]<i*add ) pos++;
            if ( a[pos]!=i*add  )
            {
                ok = false; break;
            }
            else
            {
                b[i] = pos;
            }
        }
    }
    if ( !ok ) printf ( "No\n" );
    else
    {
        printf ( "Yes\n" );
        for ( int i=1 ; i<=k ; i++ )
        {
            if ( i!=1 ) printf( " " );
            printf ( "%d" , b[i]-b[i-1] );
        }
        printf( "\n" );
    }
    return 0;
}