1. 程式人生 > >ACM-ICPC 2018 南京賽區網路預賽---總結

ACM-ICPC 2018 南京賽區網路預賽---總結

ACM-ICPC 2018 南京賽區網路預賽
總結 與ldq隊差距 4題

民間題解

A 水題 輸出 n-1

B:發現了一篇很好的部落格,講得很好
連結
類似題 :
51nod 1291 Farmer
EOJ 3514. 五彩地磚
Wannafly挑戰賽12 D
。。。。。。

my_code

#include<bits/stdc++.h>
using namespace std;
const int N = (1<<20)+5;
const long long  inf  =1e18;
typedef
long long ll; struct node { ll a,b; int pre; } p[N]; ll dp[N]; int main() { int n; cin>>n; for(int i=1; i<=n; i++) { scanf("%lld%lld",&p[i].a,&p[i].b); int vc; scanf("%d",&vc); while(vc--) { int y; scanf
("%d",&y); p[i].pre=p[i].pre|(1<<(y-1)); } } int nn = 1<<n; for(int i=0; i<nn; i++)dp[i] = -inf; dp[0]= 0; ll ans = 0; for(int i=0; i<nn; i++) { if(dp[i]==-inf)continue; ll t = 1; for(int j=1; j<=n; j++) { if
(i&(1<<(j-1)))t++; } for(int j=1; j<=n; j++) { if(i&(1<<(j-1)))continue; if(p[j].pre==0||(p[j].pre&i)>=p[j].pre) { int nxt= i|(1<<(j-1)); dp[nxt] = max(dp[nxt],p[j].a*t+p[j].b+dp[i]); ans= max(ans,dp[nxt]); } } } cout<<ans<<endl; return 0; }

I 裸的迴文樹 ,最近一直在刷這個專題,可惜了 前期題卡到最後
注意N = 10,只有10個字元,只開一個迴文樹就可以。

my_code:

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
const int MAXN = 2000008 ;
ll Pow[MAXN];
ll dp[MAXN];

char a[2000008];
const int N = 11 ;
long long ans;
struct Palindromic_Tree {
    int next[MAXN][N] ;//next指標,next指標和字典樹類似,指向的串為當前串兩端加上同一個字元構成
    int fail[MAXN] ;//fail指標,失配後跳轉到fail指標指向的節點
    long long cnt[MAXN];
    int len[MAXN] ;//len[i]表示節點i表示的迴文串的長度
    int S[MAXN] ;//存放新增的字元
    int last ;//指向上一個字元所在的節點,方便下一次add
    int n ;//字元陣列指標
    int p ;//節點指標
int  length[MAXN] ;
    int newnode ( int l ) {//新建節點
        for ( int i = 0 ; i < N ; ++ i ) next[p][i] = 0 ;
        cnt[p] = 0 ;
    //  num[p] = 0 ;
        len[p] = l ;
        return p ++ ;
    }

    void init () {//初始化
        p = 0 ;
        newnode (  0 ) ;
        newnode ( -1 ) ;
        last = 0 ;
        n = 0 ;
        S[n] = -1 ;//開頭放一個字符集中沒有的字元,減少特判
        fail[0] = 1 ;
    }

    int get_fail ( int x ) {//和KMP一樣,失配後找一個儘量最長的
        while ( S[n - len[x] - 1] != S[n] ) x = fail[x] ;
        return x ;
    }

    void add ( ll c ) {
        c -= '0' ;
        S[++ n] = c ;
        int cur = get_fail ( last ) ;//通過上一個迴文串找這個迴文串的匹配位置
        if ( !next[cur][c] ) {//如果這個迴文串沒有出現過,說明出現了一個新的本質不同的迴文串
            int now = newnode ( len[cur] + 2 ) ;//新建節點
            fail[now] = next[get_fail ( fail[cur] )][c] ;//和AC自動機一樣建立fail指標,以便失配後跳轉

            if(cur==1)
            {
                  length[now] = 1;
                  dp[now]  =c;
            }
            else if(cur==0)
            {
                length[now] = 2;
                dp[now] = c*10+c;
            }
            else
            {
                length[now] = length[cur]+2;

                dp[now]  =  (dp[cur]*10%mod+c*Pow[length[cur]+2]%mod+c)%mod;
            }
            ans+=dp[now];
            ans%=mod;
            next[cur][c] = now ;
        //  num[now] = num[fail[now]] + 1 ;
        }
        last = next[cur][c] ;
        cnt[last] ++ ;
    }


} ;
Palindromic_Tree a1;
int main()
{
    Pow[1] = 1;
    for(int i=2;i<=MAXN;i++)
    {
       Pow[i] = (Pow[i-1]*10)%mod;
    }
    a1.init();
    scanf("%s",a);
    int len= strlen(a);
    ans = 0;
    for(int i=0;i<len;i++)
    {
        a1.add(a[i]);
    }
    printf("%lld\n",ans);

    return 0;
}

G 有n間房間 每間房間有a[i]個燈泡,現在每天會買k個,有v個詢問,每次詢問第p天已經安裝好的房間數和剩餘的燈泡數,只有當前留有的燈泡數大於等於某一個房間的燈泡時才會進行安裝,安裝是按照輸入順序依次進行的。
用線段樹維護區間最小值+單點更新即可。

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lson rt<<1
#define rson rt<<1|1
#define MID int m = (l+r)/2;
const int N =200000;
struct node
{
    int v;

} tree[N<<2];
int a[N],op[N],ans1[N],ans2[N];
void push_up(int rt)
{
    tree[rt].v = min(tree[lson].v,tree[rson].v);
}
void update(int rt,int l,int r,int p,int val)
{

    if(l==r&&l==p)
    {
        tree[rt].v = val;
        return ;
    }
    MID
    if(p<=m)update(lson,l,m,p,val);
    else update(rson,m+1,r,p,val);
    push_up(rt);
}
void build(int rt,int l,int r)
{
    if(l>r)return;
    if(l==r)
    {
        tree[rt].v = a[l];
        return ;
    }
    MID
    build(lson,l,m);
    build(rson,m+1,r);
    push_up(rt);
}
int query(int rt,int l,int r,int val)
{
    if(l==r)return l;
    MID
    if(tree[lson].v<=val) return query(lson,l,m,val);
    if(tree[rson].v<=val)return query(rson,m+1,r,val);
    return -1;
}
int main()
{
    int n,k;
    cin>>n>>k;
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&a[i]);
       // update(1,1,n,i,a[i]);
    }
build(1,1,n);

    int v;
    cin>>v;
    int mx = 0;
    for(int i=1; i<=v; i++)
    {
        scanf("%d",&op[i]);
        mx = max(mx,op[i]);
    }
    int tt = 0;
    int tmp = 0;
    for(int i=1; i<=mx; i++)
    {
        tmp+=k;
        while(1)
        {
            int h = query(1,1,n,tmp);
            if(h==-1)
            {
                //tt++;
                ans1[i] = tt;
                ans2[i] = tmp;
                break;
            }
            else
            {
                tt++;
                tmp-=a[h];
                ans1[i] = tt;
                ans2[i] = tmp;
                update(1,1,n,h,0x3f3f3f3f);
            }
        }

    }
    for(int i=1; i<=v; i++)
    {
        printf("%d %d\n",ans1[op[i]],ans2[op[i]]);
    }
    return 0;
}

my_code

#include<bits/stdc++.h>
using namespace std;
const int N = 2e7+2;
bool vis[N];
long long p[N],f[N];
void init()
{
    int i,i1;
    memset(vis,0,sizeof(vis));
    f[1] = 1;
    //f[0] =1;
    int top=0;
    for(i=2;N>=i;i++)
    {
        if(vis[i]==0)
        {
            p[top++]=i;
            f[i] = 2;
        }
        for(i1=0;top>i1&&N>=p[i1]*i;i1++)
        {
            vis[i*p[i1]]=1;
            if(i%p[i1])//i裡面沒有一個p[i1]因子
            {
                f[i*p[i1]] = f[p[i1]]*f[i];
            }
            else
            {
                //if(i%(p[i1]*p[i1]))
                if((i/p[i1])%p[i1]==0)//i*p[i1]裡面有兩個及以上的因子
                {
                    f[i*p[i1]] = 0;
                }
                else //i裡面僅有一個p[i1]因子
                {
                    f[i*p[i1]] = f[i/p[i1]];
                }
               break;
            }
        }

    }
   // cout<<top-1<<endl;
   for(int i=2;i<=N;i++)
   {
       f[i] = f[i-1]+f[i];
   }
}
int main()
{
    init();
    int T;
    cin>>T;
    while(T--)
    {
        int n;cin>>n;
        cout<<f[n]<<endl;
    }
    return 0;
}
看到了別人另一種做法,也挺好 

部落格連結
https://blog.csdn.net/albertluf/article/details/82291234

L. Magical Girl Haze

把每個點拆成k+1個點建立分層圖,對於第i個點,拆成i,i+n,i+2*n...i+k*n

若原圖中i~j有一條權值為x的邊,則

add_edge(i,j,x),add_edge(i+n,j+n,x).....add_edge(i+k*n,j+k*n,x)

add_edge(i,j+n,0),add_edge(i+n,j+2*n,0)....add_edge(i+(k-1)*n,j+k*n,0)

每向上走一層相當於走了一條權值為0的邊,

假設走了(i,j+n,0)相當於從第0層走到了第一層,而把i~j這條邊的權值改為0。

最後輸出1~(k+1)*n的最短路即可。

my_code

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
long long dist[N][15];
const long long  inf =  1e18+7;
typedef pair<int,long long >ppi;
int top,head[N*2];
int n,m,k;
struct node
{
    int u,v;
    long long w;
    int next;
} edge[N*2];
struct pp{

    int v;
    long long  w;
    pp(int _v=0,long long _w=0):v(_v),w(_w){}
    bool operator<(const pp&h)const
    {
      return w>h.w;
    }
};
void addedge(int u,int v,long long  w)
{
    edge[top].v = v;
    edge[top].w = w;
    edge[top].next  = head[u];
    head[u] = top++;
}
void dijkstra()
{
    priority_queue<pp>o;
    for(int i=1; i<=n; i++)
    {
        for(int j=0; j<=12; j++)
        {
            dist[i][j]  = inf;
        }
    }
    for(int i=0; i<=10; i++)
    {
        dist[1][i] = 0;
    }
    o.push(pp(1,0));
    while(!o.empty())
    {

        pp tmp =o.top();
      //  printf("%d%d\n",o.top().first,o.top().second);
        o.pop();
        int u = tmp.v;
        for(int i=head[u]; i!=-1; i=edge[i].next)
        {
       // printf("%d\n",i);
            int v = edge[i].v;
            long long  w = edge[i].w;
            if(dist[u][0]+w<dist[v][0])
            {
                dist[v][0]  =  dist[u][0]+w;
                o.push(pp(v,dist[v][0]));
            }
            for(int j=1; j<=k; j++)
            {
                if(dist[u][j]+w<dist[v][j])
                {
                    dist[v][j]  =  dist[u][j]+w;
                    o.push(pp(v,dist[v][j]));
                }
                 if(dist[u][j-1]<dist[v][j])
                {
                    dist[v][j]  =  dist[u][j-1];
                    o.push(pp(v,dist[v][j]));
                }
            }
        }
    }

}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {

        scanf("%d%d%d",&n,&m,&k);
        memset(head,-1,sizeof(head));
        top = 0;
        for(int i=1; i<=m; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
        }
        dijkstra();
//        for(int i=1;i<=n;i++)
//        {
//        for(int j=0;j<=k;j++)
//        {
//           printf("%d ",dist[i][j]);
//        }
//        printf("\n");
//        }
        long long ans = inf;
        for(int i=0;i<=k;i++)
        {
            ans = min(dist[n][i],ans);
        }
        printf("%lld\n",ans);

    }
    return 0;
}