2018 nowcoder 多校3

这场的题还是比较有意思的,学会了很多奇奇怪怪的东西~
进度[5/10] 场上2题

A PACM Team:
这道题是一道01背包的裸题,但是不适用滚动数组的话状态有五个,需要各种优化内存,这个事情最终被其他队小伙伴做到了。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<stdlib.h>
#include<iostream>
#include<vector>
using namespace std;
typedef long long ll;
struct node
{
    int p,a,c,m,g;
} a[40];
short (*dp)[40][40][40][40];
bool (*path)[40][40][40][40];
int main()
{
    //freopen("input.txt","r",stdin);
    dp=new short[40][40][40][40][40];
    path=new bool[40][40][40][40][40];
    int n,P,A,C,M;
    cin>>n;
    for(int i=0; i<n; i++)
        cin>>a[i].p>>a[i].a>>a[i].c>>a[i].m>>a[i].g;
    cin>>P>>A>>C>>M;
    memset(dp,0,sizeof(dp));
    memset(path,0,sizeof(path));
    for(int i=0; i<n; i++)
    {
        for(int p=0; p<=P; p++)
            for(int aa=0; aa<=A; aa++)
                for(int c=0; c<=C; c++)
                    for(int m=0; m<=M; m++)
                    {
                        if(p<a[i].p || aa<a[i].a || c<a[i].c || m<a[i].m)
                            dp[i+1][p][aa][c][m]=dp[i][p][aa][c][m];
                        else
                            if(dp[i][p-a[i].p][aa-a[i].a][c-a[i].c][m-a[i].m]+a[i].g>dp[i+1][p][aa][c][m])
                            {
                                dp[i+1][p][aa][c][m]=dp[i][p-a[i].p][aa-a[i].a][c-a[i].c][m-a[i].m]+a[i].g;
                                path[i][p][aa][c][m]=1;
                            }
                   // cout<<p<<' '<<aa<<' '<<c<<' '<<m<<"----"<<dp[i][p][aa][c][m]<<"\n";

                    }
    }
    //cout<<dp[n+1][P][A][C][M]<<"\n";
   // cout<<dp[n][P][A][C][M]<<"\n";
    vector<int> v;
    for(int i=n;i>=0;i--)
    {
        if (path[i][P][A][C][M] == 1)
        {
            v.push_back(i);
            P-=a[i].p;
            A-=a[i].a;
            C-=a[i].c;
            M-=a[i].m;
        }
    }

    cout<<v.size()<<"\n";
    if(v.size()!=0)
    {
        for(int i=0; i<v.size()-1; i++)
            cout<<v[i]<<' ';
        cout<<v[v.size()-1]<<"\n";
    }

    return 0;
}

C Shuffle Cards:
这道题的意思是把一个排列的一段放到数据的最前面,然后问q次这样的操作后结果是什么样子的。
这道题一看就知道是什么搜索树,还好比赛的前一天刚好看了splay,结果就现学现卖,结果发现是板子的过,赛后重新写了下就过了

#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<algorithm>
#define N 100015
#define inf 1<<29
#define MOD 100000007
#define LL long long
#define Key_value ch[ch[root][1]][0]
#define _match(a,b) ((a)==(b))
using namespace std;
template <class T>
inline bool scan_d(T &ret)
{
    char c;
    int sgn;
    if(c=getchar(),c==EOF)
        return 0; //EOF
    while(c!='-'&&(c<'0'||c>'9'))
        c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9')
        ret=ret*10+(c - '0');
    ret*=sgn;
    return 1;
}

inline void out(int x)
{
    if(x>9)
        out(x/10);
    putchar(x%10+'0');
}
int n,q;
int size[N],pre[N],key[N],num[N],rev[N];
int ch[N][2],tot,root,node[N];
void NewNode(int &r,int k,int father)
{
    r=++tot;
    ch[r][0]=ch[r][1]=0;
    pre[r]=father;
    rev[r]=0;
    size[r] = 1;
    key[r]=k;
}
void Push_Up(int r)
{
    size[r]=size[ch[r][0]]+size[ch[r][1]]+1;
}
void Push_Down(int r)
{
    if(rev[r])
    {
        swap(ch[r][0],ch[r][1]);
        rev[ch[r][0]]^=1;
        rev[ch[r][1]]^=1;
        rev[r]=0;
    }
}
void Bulid(int &r,int L,int R,int father)
{
    if(L>R)
        return ;
    int mid=(L+R)/2;
    NewNode(r,mid,father);
    Bulid(ch[r][0],L,mid-1,r);
    Bulid(ch[r][1],mid+1,R,r);
    Push_Up(r);
}
void Init()
{
    tot=root=0;
    ch[root][0]=ch[root][1]=pre[root]=rev[root]=size[root]=0;
    NewNode(root,-1,0);
    NewNode(ch[root][1],-1,root);
    size[root]=2;
    Bulid(Key_value,1,n,ch[root][1]);
    Push_Up(ch[root][1]);
    Push_Up(root);
}
void Rotate(int x,int kind)
{
    int y=pre[x];
    Push_Down(y);
    Push_Down(x);
    ch[y][!kind]=ch[x][kind];
    pre[ch[x][kind]]=y;
    if(pre[y])
        ch[pre[y]][ch[pre[y]][1]==y]=x;
    pre[x]=pre[y];
    ch[x][kind]=y;
    pre[y]=x;
    Push_Up(y);
}
void Splay(int r,int goal)
{
    Push_Down(r);
    while(pre[r]!=goal)
    {
        if(pre[pre[r]]==goal)
            Rotate(r,ch[pre[r]][0]==r);
        else
        {
            int y=pre[r];
            int kind=(ch[pre[y]][0]==y);
            if(ch[y][kind]==r)
            {
                Rotate(r,!kind);
                Rotate(r,kind);
            }
            else
            {
                Rotate(y,kind);
                Rotate(r,kind);
            }
        }
    }
    Push_Up(r);
    if(goal==0)
        root=r;
}

int Select(int k,int g)
{
    int rt = root;
    while(size[ch[rt][0]] != k)
    {
        if(size[ch[rt][0]] > k)
        {
            rt = ch[rt][0];
        }
        else
        {
            k -= size[ch[rt][0]]+1;
            rt = ch[rt][1];
        }

    }
    Splay(rt,g);
    return rt;
}
int Get_Min(int r)
{
    Push_Down(r);
    while(ch[r][0])
    {
        r=ch[r][0];
        Push_Down(r);
    }
    return r;
}

void Cut(int a,int b,int c)
{
    Select(a - 1,0);
    Select(b+1,root);
    int w = Key_value;
    Key_value = 0;
    Splay(ch[root][1],0);
    Select(c,0);
    Select(c+1,root);
    Key_value = w;
    Splay(ch[root][1],0);
}
int cnt;
void InOrder(int r)
{
    if(r==0)
        return;
    Push_Down(r);
    InOrder(ch[r][0]);
    if(cnt>=1&&cnt<=n)
    {
        if(cnt>1)
            printf(" ");
        out(key[r]);
    }
    cnt++;
    InOrder(ch[r][1]);
}
int main()
{

    scan_d(n);scan_d(q);
    Init();
    for(int i = 0; i<q; i++)
    {
        int a,b;
        scan_d(a),scan_d(b);
        //if(a == 1 || a == n ) continue;
        Cut(a,a + b-1,0);
        //cout<<"done"<<endl;
    }
    InOrder(root);
    return 0;
}

其实还有更神奇的东邪,叫做rope,是一个pbds中的好东西,要学的东西又多了一个

#include <bits/stdc++.h>
#include <cstdio>
#include <algorithm>
#include <ext/rope>
using namespace std;
using namespace __gnu_cxx;
int main()
{
    rope<int> T;
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i =1;i<=n;i++)
    {
        T.push_back(i);
    }
    for(int i = 0;i<m;i++)
    {
        int p,s;
        scanf("%d%d",&p,&s);
        p--;
        T = T.substr(p,s)+T.substr(0,p)+T.substr(p+s,n-p-s);
    }
    for(int i = 0;i<n;i++)
    {
        printf("%d%c",T.at(i),i == n ? '\n' : ' ');
    }
    return 0;
}

H Diff-prime Pairs
这道题的题意是找出所有的pair(i,j)满足i,j <= N i/gcd(i,j) j/gcd(i,j)都是不为1的素数

有点不好想的找规律题,首先分析一下,构成解的其中一个,比如说a,b,那么a,b是素数的话肯定是可以的,此时答案是从小于n的素数中选两个方案书,除此之外,排除掉1的话,也只有ac,bc,又有ac,bc < N 则 a,b < n/c

这种情况,那我们就可以枚举c,累加此时n/c的贡献就行了

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int MAXN = 10000000;
bool check[MAXN+10];
int phi[MAXN+10];
int prime[MAXN+10];
int num[MAXN + 1];
int tot;//素数的个数
void phi_and_prime_table(int N)
{
    memset(check,false,sizeof(check));
    phi[1] = 1;
    tot = 0;
    check[1] = 1;
    for(int i = 2; i <= N; i++)
    {
        if( !check[i] )
        {
            prime[tot++] = i;
            phi[i] = i-1;
        }
        num[i] = tot;
        for(int j = 0; j < tot; j++)
        {
            if(i * prime[j] > N)
                break;
            check[i * prime[j]] = true;
            if( i % prime[j] == 0)
            {
                phi[i * prime[j]] = phi[i] * prime[j];
                break;
            }
            else
            {
                phi[i * prime[j]] = phi[i] * (prime[j] - 1);
            }
        }
    }
}
int main()
{

    int n;
    ll ans = 0;
    cin>>n;
    phi_and_prime_table(n);
    for(int i = 1;i<=n;i++)
    {
        ans += (ll)num[n/i]*(num[n/i] -1);
    }
    cout<<ans<<endl;
    return 0;
}

G Coloring Tree:
题意:给出一棵树,和K中颜色,问同种颜色节点之间最小距离都等于D的染色方案数有多少
想要直接求出来等于D的方案数有些困难,但是我们可以退而求其次,我们设F(d)代表大于等于d的方案数,这样的话就可以先求出每个点之间的间距,
利用间距信息,枚举所有的点,记录有多少个点离当前点的距离小于d,那么相对应的,这个点的染色方案就是k - cnt,如果要求每个相同颜色的点间距大于D,那么小于D的点颜色都不能是一样的,显而易见。我们之后在求一次D+1时的答案,做一次差就能求出来恰好是D次的值了

#include <iostream>
#include <cstring>
#include <queue>
#include <cstdio>
#include <algorithm>
#include <set>
#include <unordered_map>
#include <map>
typedef unsigned long long ull;
typedef long long ll;
using namespace std;
const int maxn = 5010;
const int mod = 1e9 + 7;
vector<int> edge[maxn];
int dist[maxn][maxn];
int k,n,d;
void dfs(int u,int p,int rt)
{
    for(auto v : edge[u])
    {
        if(v == p) continue;
        dist[v][rt] = dist[u][rt] +1;
        dfs(v,u,rt);
    }
}
int p[maxn];
int f(int d)
{
    for(int i = 1;i <=n;i++) p[i] = i;
    sort(p+1,p+n+1,[&](int x,int y)
         {
             return dist[1][x]< dist[1][y];
         });
    ll ans = 1;
    for(int j = 1;j<=n;j++)
    {
        int u = p[j];
        int cnt = 0;
        for(int i = 1;i<j;i++)
        {
            if(dist[u][p[i]] < d) cnt++;
        }
        if(cnt >= k) return 0;
        ans  = ans *(k - cnt)% mod;
    }
    return ans;
}
int main()
{

    scanf("%d%d%d",&n,&k,&d);
    //cin>>n>>k>>d;
    for(int i = 0;i<n-1;i++)
    {
        int u,v;
        scanf("%d %d",&u,&v);
        edge[u].push_back(v);
        edge[v].push_back(u);
    }
    for(int i = 1;i<=n;i++) dfs(i,0,i);
    int ans =( f(d) - f(d+1) ) % mod;
    if (ans <0 ) ans +=  mod;
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lingzidong/article/details/81227949