2019 杭电多校(第五场)

1002 three arrays

http://acm.hdu.edu.cn/showproblem.php?pid=6625

题意

给你两个数组 让你排序 使他们的对应异或值字典序最小

思路

https://www.bilibili.com/video/av62396512?from=search&seid=2029202226881211707

代码

(调自闭了 请队友帮的忙(01字典树多跑了一位 初始化函数没有调用))

#include 

using namespace std;
typedef long long ll;
const int maxn = 1e5+100;
int a[maxn],b[maxn];
int tree[50*maxn][2],tree2[50*maxn][2];
int num[50*maxn],num2[50*maxn];
int tot,tot2,top;
int n;
int ans[maxn];
int qw[40];
void init()
{
    tot = tot2 = 1;
    top = 0;
    tree[0][0] = tree[0][1] = tree2[0][1] = tree2[0][0] = 0;
}
void add(int x)
{
    int u = 0;
    for(int i = 29;i >= 0;i--)
    {
        int v = (x>>i)&1;
        if(tree[u][v] == 0)
        {
            tree[tot][0] = tree[tot][1] = 0;
            num[tot] = 0;
            tree[u][v] = tot++;
        }

        u = tree[u][v];
        num[u]++;
    }
}
void add2(int x)
{
    int u = 0;
    for(int i = 29;i >= 0;i--)
    {
        int v = (x>>i)&1;
        if(tree2[u][v] == 0)
        {
            tree2[tot2][0] = tree2[tot2][1] = 0;
            num2[tot2] = 0;
            tree2[u][v] = tot2++;
        }
        u = tree2[u][v];
        num2[u]++;
    }
}

void dfs(int x1,int x2,int len,int res,int sum)
{
    if(len == 31)
    {
        for(int i = 1;i <= sum;i++)
        {
            ans[++top] = res;
        }
        return ;
    }

    int l = num[tree[x1][0]],r = num[tree[x1][1]];
    int ll = num2[tree2[x2][0]],rr = num2[tree2[x2][1]];

    if(l>0&&ll>0)
    {
        int mi = min(l,ll);
        mi = min(mi,sum);
        l -= mi,ll -= mi;
        dfs(tree[x1][0],tree2[x2][0],len+1,res,mi);
        num[tree[x1][0]] -= mi,num2[tree2[x2][0]] -= mi;
    }
    if(r>0&&rr>0)
    {
        int mi = min(r,rr);
        mi = min(mi,sum);
        r -= mi,rr -= mi;

        dfs(tree[x1][1],tree2[x2][1],len+1,res,mi);
        num[tree[x1][1]] -= mi,num2[tree2[x2][1]] -= mi;
    }
    if(l>0&&rr>0)
    {
        int mi = min(l,rr);
        mi = min(mi,sum);
        l -= mi,rr -= mi;
        dfs(tree[x1][0],tree2[x2][1],len+1,res^qw[29-len+1],mi);
        num[tree[x1][0]] -= mi,num2[tree2[x2][1]] -= mi;
    }
    if(r>0&&ll>0)
    {
        int mi = min(r,ll);
        mi = min(mi,sum);
        r -= mi,ll -= mi;
        dfs(tree[x1][1],tree2[x2][0],len+1,res^qw[29-len+1],mi);
        num[tree[x1][1]] -= mi,num2[tree2[x2][0]] -= mi;
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    qw[0] = 1;
    for(int i = 1;i <= 30;i++)
    {
        qw[i] = qw[i-1]*2;
    }
    while(T--)
    {
        init();
        int n;
        scanf("%d",&n);
        for(int i = 1;i <= n;i++)
        {
            scanf("%d",&a[i]);
            add(a[i]);
        }
        for(int i = 1;i <= n;i++)
        {
            scanf("%d",&b[i]);
            add2(b[i]);
        }

        dfs(0,0,1,0,n);
        sort(ans+1,ans+1+n);
        for(int i = 1;i <= n;i++)
        {
            if(i != 1) printf(" ");
            printf("%d",ans[i]);
        }
        printf("\n");
    }
    return 0;
}


做法二

#include 

using namespace std;
const int maxn = 1e5+100;
int tree[maxn*40][2],tree2[maxn*40][2];
int num[maxn*40],num2[maxn*40];
int val[maxn*40],val2[maxn*40];
int tot,tot2,top;
int a[maxn],b[maxn];
map mp;
int n;
int ans[maxn];
void init()
{
    tot = tot2 = 1;
    top = 0;
    tree[0][0] = tree[0][1] = tree2[0][0] = tree2[0][1] = 0;
    mp.clear();
}
void add(int x)
{
    int u = 0;
    for(int i = 29;i >= 0;i--)
    {
        int v = (x>>i)&1;
        if(tree[u][v] == 0)
        {
            tree[tot][0] = tree[tot][1] = 0;
            num[tot] = 0;
            tree[u][v] = tot++;
        }
        u = tree[u][v];
        num[u]++;
    }
    val[u] = x;
}
void add2(int x)
{
    int u = 0;
    for(int i = 29;i >= 0;i--)
    {
        int v = (x>>i)&1;
        if(tree2[u][v] == 0)
        {
            tree2[tot2][0] = tree2[tot2][1] = 0;
            num2[tot2] = 0;
            tree2[u][v] = tot2++;
        }
        u = tree2[u][v];
        num2[u]++;
    }
    val2[u] = x;
}
int query(int x)
{
    int u = 0;
    for(int i = 29;i >= 0;i--)
    {
        int v = (x>>i)&1;
        if(num[tree[u][v]])
        {
            u = tree[u][v];
        }
        else u = tree[u][v^1];
    }
    return val[u];
}
int query2(int x)
{
    int u = 0;
    for(int i = 29;i >= 0;i--)
    {
        int v = (x>>i)&1;
        if(num2[tree2[u][v]])
        {
            u = tree2[u][v];
        }
        else u = tree2[u][v^1];
    }
    return val2[u];
}
int updata(int x,int y)
{
    int u = 0;
    for(int i = 29;i >= 0;i--)
    {
        int v = (x>>i)&1;
        u = tree[u][v];
        num[u]+=y;
    }
}
int updata2(int x,int y)
{
    int u = 0;
    for(int i = 29;i >= 0;i--)
    {
        int v = (x>>i)&1;
        u = tree2[u][v];
        num2[u]+=y;
    }
}

int main()
{
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--)
    {
        init();
        cin>>n;
        for(int i = 1;i <= n;i++)
        {
            cin>>a[i];
            add(a[i]);
            mp[a[i]]++;
        }
        for(int i = 1;i <= n;i++)
        {
            cin>>b[i];
            add2(b[i]);
        }
        int p = 1;
        int aa,bb,cc;
        while(p <= n)
        {
            if(mp[a[p]] == 0)
            {
                p++;
                if(p > n) break;
                continue;
            }
            aa = a[p];
            bb = query2(aa);
            cc = query(bb);
            while(cc != aa)
            {
                aa = cc;
                bb = query2(aa);
                cc = query(bb);
            }

            ans[++top] = aa^bb;
            updata(aa,-1);
            updata2(bb,-1);
            mp[aa]--;
        }
        sort(ans+1,ans+1+n);
        for(int i = 1;i <= n;i++)
        {
            if(i != 1) printf(" ");
            printf("%d",ans[i]);
        }
        printf("\n");
    }
    return 0;
}

1004 equation (数学)

http://acm.hdu.edu.cn/showproblem.php?pid=6627

题意

给你一个方程 求解

思路

对于绝对值 不同的区间去绝对值后式子不同 即会有(n+1)个求解区间 分别求解即可

代码

#include 

using namespace std;
const int maxn = 1e5+100;
struct node
{
    int a,b;
    double x;
    int id;
}qw[maxn],ans[maxn];
int a[maxn],b[maxn];
int n, c, A, B;
double l,r;
queue q;
int f;

bool cmp(node a,node b)
{
    if(a.x != b.x) return a.x < b.x;
    else return a.id < b.id;
}

void solve()
{
    if(A==0&&B == c)
    {
        f = 1;
        return ;
    }
    double ans;
    ans = (double)(c-B)/A;
    if(ans  > l&&ans <= r)
    {
        int as = 1;
        if(ans < 0) as = -1;
        int x = (c - B),y = A;
        x = abs(x),y = abs(y);
        int z;
        if(x == 0) z =  y;
        else z = __gcd(x,y);
        node u;
        u.a = x / z * as,u.b = y / z;
        q.push(u);
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
         scanf("%d%d",&n,&c);
         A = 0,B = 0;
         for(int i = 1;i <= n;i++)
         {
             scanf("%d%d",&a[i],&b[i]);
             qw[i].a = a[i],qw[i].b = b[i];
             qw[i].id = i;
             qw[i].x = (double)b[i]/a[i]*(-1.0);
             A += -a[i],B += -b[i];
         }
         sort(qw+1,qw+1+n,cmp);
         f = 0;
         while(!q.empty()) q.pop();
         l = -1e18,r = -1e18;
         qw[n+1].x = 1e18;

         for(int i = 1;i <= n+1;i++)
         {
             l = r,r = qw[i].x;
             solve();
             A += qw[i].a*2;
             B += qw[i].b*2;
         }
         if(f) printf("-1\n");
         else
         {
             printf("%d",q.size());
             while(!q.empty())
             {
                 node u = q.front();
                 q.pop();

                 printf(" %d/%d",u.a,u.b);
             }
             printf("\n");
         }
    }
    return 0;
}

1005 permutation 1 (思维)

http://acm.hdu.edu.cn/showproblem.php?pid=6628

题意

给你n个数  1 到 n  问你全排列相邻差字典序第k大的是哪个

思路

k最大10000 8个数即可 n小于8位之间暴力 大于8位直接填最后8位之前 最大8位暴力

#include
using namespace std;
typedef long long ll;
struct node
{
    int a[30];

} qw[1000000];
int vis[30];
int p,n,m;
int xx[30];

bool cmp(node a,node b)
{
    for(int i = 2; i <= m; i++)
    {
        if(a.a[i]-a.a[i-1]!= b.a[i] - b.a[i-1])
        {
            return a.a[i]-a.a[i-1] < b.a[i] - b.a[i-1];
        }
    }
}

void dfs(int x)
{
    if(x == m+1)
    {
        p++;
        for(int i = 1; i <= m; i++)
        {
            qw[p].a[i] = xx[i];
        }
        return ;
    }
    for(int i = 1; i <= n; i++)
    {
        if(vis[i] == 0)
        {
            vis[i] = 1;
            xx[x] = i;
            dfs(x+1);
            vis[i] = 0;
        }
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int k;
        scanf("%d%d",&n,&k);
        m = n;
        p = 0;
        memset(vis,0,sizeof(vis));
        if(n <= 8)
        {
            dfs(1);
            sort(qw+1,qw+1+p,cmp);
            for(int i = 1; i <= n; i++)
            {
                if(i != 1)
                    printf(" ");
                printf("%d",qw[k].a[i]);
            }
            printf("\n");
        }
        else
        {
            printf("%d",n);
            vis[n] =1;
            for(int i = 1; i <= n - 8 - 1; i++)
            {
                printf(" %d",i);
                vis[i] = 1;
                xx[1] = i;
            }
            m = 9;
            dfs(2);
            sort(qw+1,qw+1+p,cmp);
            for(int i = 2; i <= m; i++)
            {
                printf(" %d",qw[k].a[i]);
            }
            printf("\n");

        }
    }
    return 0;
}

1006 string matching (扩展kmp)

http://acm.hdu.edu.cn/showproblem.php?pid=6629

题意

给你一个字符串 问从第2位 每一位和字符串相等前缀多长 (比较多少次 直到完全匹配 或 失败)

思路

拓展kmp 注意完全匹配时不需要加一次失败匹配

代码

#include
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
typedef long long ll;
char s[N];
int nex[N],extend[N];
ll sum;
void get_next()
{
    int len = strlen(s);
    nex[0] = len;
    int mx = 0,id;
    for(int i = 1;i < len;i++)
    {
        if(i < mx) nex[i] = min(mx-i,nex[i-id]);
        else nex[i] = 0;
        while(s[i+nex[i]] == s[nex[i]]) nex[i]++;
        if(mx < i + nex[i])
        {
            id = i;
            mx = i + nex[i];
        }

        sum += (ll)min(nex[i]+1,len-i);
    }
}


int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%s",s);
        sum = 0;
        get_next();
        ll n = strlen(s);
       printf("%lld\n",sum);
    }
    return 0;
}

1007 permutation 2

http://acm.hdu.edu.cn/showproblem.php?pid=6630

题意

给你n个数 1-n  给你其中两个做第一和最后 打其他数填到里面 有多少种填法

思路

很容易想到如果第一位不是1 要把1-x-1填成 1 ...... x-1

最后一位不是n n后面要填成  y-1......y

中间就是 dp[i] = dp[i-1] + dp[i-3] 

代码

#include
using namespace std;
typedef long long ll;
const ll mod = 998244353;
ll dp[100005];
int main()
{
    int T;
    scanf("%d",&T);
    dp[1] = 1;
    dp[2] = 1;
    dp[3] = 1;
    for(int i = 4;i <= 100000;i++)
    {
        dp[i] = dp[i-1] + dp[i-3];
        dp[i] %= mod;
    }
    while(T--)
    {
        ll n,x,y;
        scanf("%lld%lld%lld",&n,&x,&y);
        if(x > y) swap(x,y);
        if(x != 1) x++;
        if(y != n) y--;
        printf("%lld\n",dp[y-x+1]);
    }
    return 0;
}

 

你可能感兴趣的:(#,2019,杭电多校)