ACM-ICPC 2018 南京赛区网络预赛---总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/axuhongbo/article/details/82313361
ACM-ICPC 2018 南京赛区网络预赛
总结 与ldq队差距 4题

民间题解

A 水题 输出 n-1


B:发现了一篇很好的博客,讲得很好
链接
类似题 :
51nod 1291 Farmer
EOJ 3514. 五彩地砖
Wannafly挑战赛12 D
。。。。。。


E 裸状压dp http://www.cnblogs.com/dilthey/p/9570205.html

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个字符,只开一个回文树就可以。

马拉车+hash做法
使劲疯大佬改的原题代码
https://www.cnblogs.com/hua-dong/p/7714475.html
https://paste.ubuntu.com/p/g7MMNt87KJ/

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;
}

J 6发罚时 题目链接 https://nanti.jisuanke.com/t/30999
学长o(n)素数筛模板 https://blog.csdn.net/a15110103117/article/details/81637569

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;
}

L 赛中被pair卡常
补题链接:https://blog.csdn.net/axuhongbo/article/details/82289535

看到了别人另一种做法,也挺好 

博客链接
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;
}

猜你喜欢

转载自blog.csdn.net/axuhongbo/article/details/82313361