ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

开坑难填之A层邀请赛1

2022-08-14 09:31:15  阅读:100  来源: 互联网

标签:ch const int ll 开坑 maxn ans 邀请赛


A. Race

据说很容易想到Trie树?但我当时只想到了暴力……(原因是Trie树还不会qwq)

//我相信我没分~
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 2e5 + 3;
const ll mod = 998244353;

int m, n, a[maxn];
ll r[maxn], ans;
struct node 
{
    int id;
    ll val;
    bool operator < (const node &T) const 
    {
        return T.val < val;
    }
}c[maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

int main()
{
    n = read(); m = read();
    for(int i=1; i<=n; i++) a[i] = read();

    int Day = (1<<m);
    for(int j=0; j<Day; j++)
    {
        //printf("j = %d\n", j);
        for(int i=1; i<=n; i++)
        {
            c[i].val = (a[i]^j);
            c[i].id = i;
            //printf("c[%d].val = %lld\n", i, c[i].val);
        }
        sort(c+1, c+1+n);
        /*for(int i=1; i<=n; i++)
        {
            printf("%lld\n", c[i].val);
        }*/
        for(int i=1; i<=n; i++)
        {
            int id = c[i].id;
            r[id] = (r[id]+(ll)(i-1)*(i-1))%mod;
        }
    }
    for(int i=1; i<=n; i++)
    {
        ans ^= r[i];
        //printf("r[%d] = %lld\n", i, r[i]);
        //printf("ans = %lld\n", ans);
    }
    printf("%lld", ans);
    
    return 0;
}
TLE 10

正解:先把x^2拆开变成(x1+x2+x3+...)*(x1+x2+x3+...)其中每一个xi都为1,代表当天更大的数,再继续展开就变成了(x1^2+x2^2+...+2*x1*x2+2*x1*x3+...),所以答案就和在它之前的点对的个数有了关系。

对每一个a[i],枚举在a[i]之前的点对,其中一个是从M-1到j-1异或值和a[i]相同,另一个是从M-1到k-1和a[i]相同,它们分别在第j位和第k位比a[i]的对应位大,find是找到前面的对应位相同,ch^1是当前位和a[i]相反,而单独找到相反还不够可能异或更小了,这就给天数设置了限制条件,一定可以找到满足条件的日子因为它所有位都是满的。j==k的情况是1<<(M-1)因为对M的限制只有一位。

这个应该不算是按位计算贡献吧,只是把位拆开来枚举点对而已……不过这么说好像也可以?

找点对的时候避免重复把k循环到j-1而不是把k==j continue掉。点对当然可以合并(在计算贡献时用树上的size),因为点对本来就是拆开的,拆成几个都一样。

#include <bits/stdc++.h>
  
using namespace std;
  
typedef long long ll;
const int maxn = 5e5 + 5;
const int N = 1e7 + 2;
const int mod = 1e9 + 7;
const int INF = 1061109567;

int n, M, tot=1, fa[maxn][31];
ll ans[maxn], sum, a[maxn];
struct node 
{
    ll ch[2], size;
}t[maxn*20];
  
inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

void insert(int x)
{
    int p = 1; t[p].size++; fa[x][M] = 1;
    for(int i=M-1; i>=0; i--)
    {
        int me = (a[x]>>i)&1;
        if(!t[p].ch[me]) t[p].ch[me] = ++tot;
        p = t[p].ch[me];
        t[p].size++;
        fa[x][i] = p;
    }
}

void work(int x)
{
    for(int i=0; i<=M-1; i++)
    {
        int me1 = 0, find1 = 0, me2 = 0, find2 = 0;
        for(int j=0; j<i; j++)
        {
            me1 = (a[x]>>i)&1; me2 = (a[x]>>j)&1;
            me1^=1; me2^=1;
            find1 = fa[x][i+1]; find2 = fa[x][j+1];
            ans[x] = (ans[x]+2*t[t[find1].ch[me1]].size*t[t[find2].ch[me2]].size%mod*(1ll<<(M-2ll))%mod)%mod;
        }
        me1 = (a[x]>>i)&1; me1^=1;
        find1 = fa[x][i+1];
        ans[x] = (ans[x]+t[t[find1].ch[me1]].size*t[t[find1].ch[me1]].size%mod*(1ll<<(M-1ll))%mod)%mod;
    }
}

int main()
{
    n = read(); M = read();
    for(int i=1; i<=n; i++)
    {
        a[i] = read();
    }
    for(int i=1; i<=n; i++)
    {
        insert(i);
    }  
    for(int i=1; i<=n; i++)
    {
        work(i);
    }
    for(int i=1; i<=n; i++)
    {
        sum ^= ans[i];
    }
    printf("%lld\n", sum);
  
    return 0;
}
View Code

 

B. 青蛙

赛时正解好像我也想到了,不会数cnt+1……WA 0……

如果这些石头连一只青蛙不付代价地跳过去都不够,那就让代价最小的青蛙把所有石头跳一遍,其他青蛙直接从头到尾;如果这些石头可以让至少一只青蛙不付代价地跳过去,那就尽可能让代价大的去跳石头,每次卡着上限去跳给其他青蛙也留足机会,不用考虑石头有剩余,直接分配给能跳过去的某只青蛙就好了,距离只会减得更小,一次跳不过去的青蛙直接从头到尾。

那种卡上限跳的思路可以用set实现,虽然有log不过据说可以过,但当时这么想纯属瞎蒙,并不会证明,于是我去借鉴了双指针的方法——%%%Chen_jr%%%妙不可言

讲题那天好像就是这么讲的,蒟蒻直到看见代码才知道说的是什么意思……

#include <bits/stdc++.h>
  
using namespace std;
  
typedef long long ll;
const int maxn = 5e5 + 5;
const int N = 1e7 + 2;
const int mod = 1e9 + 7;
const int INF = 1061109567;

int T, n, m, k, d, c[maxn], a[maxn];
bool f[maxn];
  
inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

int main()
{
    T = read();
    while(T--)
    {
        n = read(); m = read(); k = read(); d = read();
        for(int i=1; i<=m; i++)
        {
            c[i] = read();
        }
        for(int i=1; i<=k; i++)
        {
            a[i] = read();
        }
        sort(a+1, a+k+1); sort(c+1, c+m+1);
        int p = 0, cnt = 0;
        for(int i=0; i<=k; i++) f[i] = 0;//memset
        for(; p<=k; p++)
        {
            if(a[p]-1 <= d) f[p] = 1;//表示有青蛙跳到了第p个石头上
            else break;
        }
        for(int i=1; i<=k; i++)
        {
            //为什么不判断f[p]不能是1,因为p跳完就往后增加,当然不可能是1
            if(f[i] && a[p]-a[i]<=d && p <= k)//从有青蛙的石头开始向后转移,最靠左的青蛙尝试最近的空石头
            {
                f[p] = 1; f[i] = 0; p++;//青蛙跳走了记得清空
            }
        }
        for(int i=k; i>=1; i--)//然后还要能到终点才行
        {
            if(n-a[i] <= d && f[i]) cnt++;
            else break;
        }
        ll ans = 0;
        if(cnt == 0)
        {
            a[0] = 1; a[k+1] = n;
            for(int i=1; i<=k+1; i++)
            {
                if(a[i]-a[i-1] > d) ans += c[1];
            }
            ans -= c[1];//因为后面没有else,c[1]又加了一遍
        }
        for(int i=1; i<=m-cnt; i++)
        {
            ans += c[i];
        }
        printf("%lld\n", ans);
    }
  
    return 0;
}
View Code

 

C. 序列

首先,暴力可以水个25分。然后,吉斯机线段树是什么鬼啊,容我先去学习一下……

 

标签:ch,const,int,ll,开坑,maxn,ans,邀请赛
来源: https://www.cnblogs.com/Catherine2006/p/16584801.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有