第十二次新生排位赛

第十二次新生排位赛

第一题

  1. Study sister's barbarian
    时间限制 2000 ms 内存限制 65536 KB
    题目描述
    Study sister plays the game coc everyday. When she wants to attack another clan, Study brothers will donate a lot of barbarian to help her.
    We assume that there are n Study brothers and each of them send one barbarian to help Study sister. The barbarians had different hitpoints, and they had to stand in one line when they get out of the clan.
    Some Study brothers wants to impress Study sister, so they wants their own barbarian become the ai-th barbarian that get out of the clan. We know that Study brothers donate their barbarian in turn, so the order they choose when they donate the army may not be the final order. Now given the donating behavior in order, Study sister wants to know the final sequence of barbarian by their hitpoints.

输入格式
There are several test case. Each test case begin with a sigal integer n(1<=n<=200000), means the number of Study brothers. Next n line, each line contains two integer a, b, means the i-th Study brother wants his barbarian become the a-th army that get out of the clan, and its hitpoints is b. 0<=a<i, 0<=b<100000.

There are break line between each test case.

输出格式
For each case, print one line, the final sequence of barbarian by their hitpoints.

输入样例
4
0 77
1 51
1 33
2 69
输出样例
77 33 69 51

hint:
the process are:
a barbarian of 77 hitpoints wants to become the 0-th, now the sequence becomes: 77
a barbarian of 51 hitpoints wants to become the 1-th, now the sequence becomes: 77 51
a barbarian of 33 hitpoints wants to become the 1-th, now the sequence becomes: 77 33 51
a barbarian of 69 hitpoints wants to become the 2-th, now the sequence becomes: 77 33 69 51

这题是poj原题2828,可以用树状数组加二分来做,也可以用线段树来做,由于线段树已带二分性质,所以比线段树快了一半的时间 题目主要的一个思想是逆序思考。假设共有n个数,最后一个放进去的肯定放在他所指定i-th的位置,倒数第二个放在剩下的空格的第i-th,所以题目转变成了计算当前第i-th空格实际位置在哪里。可以预处理n个位置原来都是0, 放一个就是该位置变成1,某一个位置pos(包括它自己)前面的空格的个数就是pos - sum(pos);当然也可以预处理n个位置原来都是1, 放一个就是该位置-1变成0,某一个位置pos(包括它自己)前面的空格的个数就是sum(pos);strong text

c++
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cmath>

using namespace std;
int ans[200005];
int a[200005];
int b[200005];
int c[200005];
int n;
void update(int pos, int w)
{
    while(pos<=n)
    {
        c[pos] += w;
        pos += pos&-pos;
    }
}
int sum(int pos)
{
    int ans=0;
    while(pos)
    {
        ans+=c[pos];
        pos -= pos&-pos;
    }
    return ans;
}
int get(int pos)//二分查找位置
{
    int head=1;
    int last=n;
    int mid=(head+last)/2;
    int t=mid-sum(mid);
    while (t!=pos)
    {
        if (t>pos)
        {
            last = mid;
        }
        else head = mid+1;
        mid=(head+last)/2;
        t=mid-sum(mid);
    }
    return mid;
}

int main()
{
    while (~scanf("%d", &n))
    {
        int a1, b1;
        for (int i=1; i<=n; i++)
        {
            scanf("%d %d", &a1, &b1);
            a[i] = a1+1;
            b[i] = b1;
            c[i] = 0;
        }
        for (int i=n; i>0; i--)
        {
            int t = get(a[i]);
            while (ans[t]!=-1) t--;
            ans[t] = b[i];
            update(t, 1);
        }
        for (int i=1; i<=n; i++)
        {
            printf("%d", ans[i]);
            if (i<n) printf(" ");
        }
        printf("\n");

    }
    return 0;
}






学长的代码

c++
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const int N = 200200;
const int oo = 0x3f3f3f3f;
typedef unsigned long long LL;
pair<int,int >a[N];
int ans[N];
int s[N];
int n;
void add(int p,int d)
{
    if(p==0)s[0]++;
    else
        for(;p<=n;p+=lowbit(p))
            s[p]+=d;
}
int sum(int p)
{
    int ss=s[0];
    for(;p>=1;p-=lowbit(p))
        ss+=s[p];
    return ss;
}
int main()
{
    int tit,tot;
    //scanf("%d",&tot);
    for(tit=1;~scanf("%d",&n);tit++)
    {
        for(int i=1;i<=n;i++)
            scanf("%d%d",&a[i].first,&a[i].second);
        memset(s,0,sizeof(s));
        for(int i=n;i>=1;i--)
        {
            int low=0,up=n;
            while(low+1!=up)
            {
                int mid=(low+up)/2;
                if(mid-sum(mid-1)<=a[i].first)low=mid;
                else up=mid;
            }
            //cout<<".."<<low<<endl;
            add(low,1);
            ans[low]=a[i].second;
        }
        for(int i=0;i<n;i++)
            printf("%d%c",ans[i],i==n-1?'\n':' ');
    }
    return 0;
}

线段树

c++
#define maxn 200010
#define lson l,m,rt << 1
#define rson m + 1, r, rt << 1 | 1
#define ls rt << 1
#define rs rt << 1 | 1
#define havem int m = (l + r) >> 1
#include <cstdio>
using namespace std;
int ans[maxn],val[maxn],pos[maxn],sum[maxn << 2],n;
void build(int l , int r, int rt){
    sum[rt] = r - l + 1;
    if(l == r) return;
    havem;
    build(lson); build(rson);
}
int getpos(int pos, int l, int r, int rt){//返回的是第pos[] + 1的空位的下标
    sum[rt] --;
    if(l == r) {
        return l;
    }havem;
    if(sum[ls] >= pos) return getpos(pos,lson);
    else return getpos(pos - sum[ls],rson);//就在右儿子里面去找pos - sum[ls]
}
int main(){
    while(~scanf("%d",&n)){
        for(int i = 1; i <= n; i ++)
            scanf("%d%d",&pos[i],&val[i]);
        build(1,n,1);
        for(int i = n; i >= 1; i --){//从后往前依次插入
            ans[getpos(pos[i] + 1, 1,n,1)] = val[i];
        }
        for(int i = 1;i < n;i ++){
            printf("%d ",ans[i]);
        }printf("%d\n",ans[n]);
    }
    return 0;
}

后面两个显然都不是我的代码,风格就不一样嘛^_^

第二题

  1. Study brothers wanna join clan
    时间限制 10000 ms 内存限制 65536 KB
    题目描述
    Some study brothers wanna join our clan,but they don't know whether they will be received.
    As we know,vegetable chickens prefer to make friends with tuhaoes and vice versa.However,vegetable chickens don't want to make friends with someone like them,just as tuhaoes think.And how to measure somebody?Now we define pair(x,y) to measure someone's property ,whick x means how much holy water you have and y means how much money you have.And how to know how popular you are?We measure it by popularity which is the sum of Chebyshev distance with each other in the clan.Maybe you don't know the Chebyshev distance with two person,so let me tell you.The Chebyshev distance with (x1,y1) and (x2,y2) is just max(abs(x1-x2),abs(y1-y2)).

Now before joining our clan,these study brothers ask you to help them know their popularities if they join.

输入格式

The input consists of no more than 10 cases,and end with EOF.
In the first line of each case,you will get two integers N and M which means the number of people in the clan now and the number of study brothers to join (1<=N,M<=1e5).
Then there are N lines,and in each line you will get two numbers xi,yi which are used to measure the ith person in the clan.
Then there are M lines,and in each line you will get two numbers xi,yi which are used to measure the ith study brothers. (xi,yi<=1e9)

输出格式

For each case,print the popularity of each study brother in one line.

输入样例
3 3
0 3
3 0
2 2
1 0
0 1
4 4
输出样例
7
7
10

hint
for 1 0: max(abs(1,0),abs(0,3)) + max(abs(1,3),abs(0,0)) + max(abs(1,2),abs(0,2)) = 7
for 0 4: max(abs(0,0),abs(4,3)) + max(abs(0,3),abs(4,0)) + max(abs(0,2),abs(4,2)) = 7
for 4 4: max(abs(4,0),abs(4,3)) + max(abs(4,3),abs(4,0)) + max(abs(4,2),abs(4,2)) = 10

这题要求的是切比雪夫距离max(abs(x1-x2),abs(y1-y2)),但是一般我们我们会转化成曼哈顿距离abs(x1-x2)+abs(y1-y2),

两者的转化公式是求(x1,y1)的切比雪夫距离,相当于求((xi-yi)/2, (xi+yi)/2)的曼哈顿距离,这个写两个,用数学推导一下就行
同理求(x1,y1)的曼哈顿距离,相当于求(xi-yi, xi+yi)的切比雪夫距离

接下来把转化后的x,y坐标分开两个数组计算一下,排排序,这个和之前一道题目很像

c++
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cmath>

using namespace std;

int a[2][100005];
long long sum[2][100005];
int tap[2][100005];
int num[2][100005];
int tot[2];
int n, m;
void solve(int t)
{
    sum[t][0] = a[t][0];
    num[t][0] = 1;
    tap[t][0] = a[t][0];
    tot[t] = 0;
    for (int i=1; i<n; i++)
    {
        if (a[t][i]>a[t][i-1])
        {
            tot[t]++;
            num[t][tot[t]] = num[t][tot[t]-1];
            sum[t][tot[t]] = sum[t][tot[t]-1];
            tap[t][tot[t]] = a[t][i];
        }
        sum[t][tot[t]] += a[t][i];
        num[t][tot[t]] ++;
    }
}

long long seek(int t, int pot)
{
    long long ans = 0;
    int pos = lower_bound(tap[t], tap[t]+tot[t]+1, pot)-tap[t];
    ans = (long long)num[t][pos-1]*pot*2-sum[t][pos-1]*2+sum[t][tot[t]]-(long long)n*pot;

    return ans;
}

int main()
{
    while(~scanf("%d %d", &n, &m))
    {
        int x, y;
        for (int i=0; i<n; i++)
        {
            scanf("%d %d", &x, &y);
            a[0][i] = x+y;
            a[1][i] = y-x;
        }
        sort(a[0], a[0]+n);
        sort(a[1], a[1]+n);
        solve(0);
        solve(1);
        long long ansd;
        for (int i=0; i<m; i++)
        {
            ansd = 0;
            scanf("%d %d", &x, &y);
            ansd += seek(0, x+y);
            ansd += seek(1, y-x);
            printf("%lld\n", ansd/2);
        }
    }

    return 0;
}

第三题
主题思想是怎么用好欧拉函数

首先预处理求10000(最大数开根号)范围内的素数
因为10^8内的质因子除了它自己就是10^4以内的质数了
然后求n的质因子,以及每个质因子的a,( a是使得p^a整除n的最大整数a )
接下来把n拆成两个正整数的乘积a*b ,
ans += k^a*ψ(b) + k^b*ψ(a);
这是个神奇的公式,至于怎么推导我还要继续学习
求ψ(a)ψ(b)(即a,b的欧拉函数值)可以利用之前n的质因子,这样减少了很多运算量

至于求哪些a*b可以组成n,这题可以遍历也可以,根据已经知道质因子dfs求可能因子

预处理求素数有两种代码,目前不知速度相比如何,所以暂时先都放上

c++
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#define mod 23333
#define eps 1e-9

using namespace std;

int pri[10005];
int tot, t;
bool nop[10005];
int np[100];
int num[100];
int n, k;
void fprime()//预处理求素数
{
    tot = 1;
    pri[0]=2;
    int flag;
    for (int j=3; j<10000; j++)
    {
        flag = 1;
        for (int i=0; i<tot; i++)
        {
            if (j%pri[i]==0)
            {
                flag = 0;
                break;
            }
        }
        if (flag)
            pri[tot++] = j;
    }
}
//因为这个快速幂是不能取模的,所以另外开了一个
int qpow2(int k, int n)
{
    int ans = 1;
    while (n)
    {
        if (n&1)
        {
            ans = ans*k;
        }
        n >>= 1;
        k = k*k;
    }
    return ans;
}


long long qpow(long long k, int n)
{
    long long ans = 1;
    while (n)
    {
        if (n&1)
        {
            ans = ans*k%mod;
        }
        n >>= 1;
        k = k*k%mod;
    }
    return ans;
}
int nfun(int n)//预处理n
{
    t = 0;
    for (int i=0; (i<tot)&&(n!=1); i++)
    {
        if (pri[i]>sqrt(n)+eps)
        {
            np[t] = n;
            num[t++] = 1;
            break;
        }
        if (n%pri[i]==0)
        {
            np[t] = pri[i];
            num[t] = 0;
            while (n%pri[i]==0)
            {
                num[t] ++;
                n = n/pri[i];
            }
            t++;
        }
    }
}

int efun(int p)
{
    int ans = p;
    if (p==1) return 1;
    for (int i=0; i<t; i++)
    {
        if (p%np[i]==0)
        {
            ans = ans/np[i]*(np[i]-1);
        }
    }
    return ans%mod;
}

long long ansd;
//int tg;

void dfs(int a, int pos)
{
    if (pos>=t)
    {
        long long qew = qpow(k, a)*efun(n/a)%mod;
        ansd = (ansd+qew)%mod;
        //cout << a << " " << qew << endl;
        //tg++;
        return;
    }
    for (int i=0; i<=num[pos]; i++)
    {
        int t = a;
        dfs(t*qpow2(np[pos], i), pos+1);
    }
}

int main()
{
    fprime();
    int t;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%lld %d", &k, &n);
        ansd = 0;
        nfun(n);
        tg = 0;
        dfs(1, 0);
        printf("%lld\n", ansd);

    }

    return 0;
}
c++
void fprime()
{
    memset(nop, 0, sizeof nop);
    tot = 1;
    pri[0]=2;
    int flag;
    for (int j=3; j<10000; j+=2)
    {
        if (!nop[j])
        {
            for (int k=j*3; k<10000; k+=j*2)
                nop[k] = true;
            pri[tot++] = j;
        }
    }
}

第四题

  1. Study sister's wizard
    时间限制 1000 ms 内存限制 65536 KB
    题目描述
    Study sister plays the game coc everyday. Now she wants to upgrade her wizard in laboratory,but she doesn't know the spell. After research, she finds out that the spells are made by repeat the keyword M times. She checks top players' daily log and get one of their upgrade log.
    Now she wants to know how many possible spells are in the log.

输入格式
There are several test cases. For each case, the first line consist of two integer M, L, (M*L <= 1e5) means the repeat time and the lenth of the keyword. Next line contains a string means the log. The string is made by lowercase letter.

update: |s| <=1e5

输出格式
For each test case, print one line, the number of the possible spells.

输入样例
3 3
abcabcabcabc
输出样例
4

hint:
The four possible spells are:
abcabcabc
bcabcabca
cabcabcab
abcabcabc

这题,注意要用规范的哈希,当时没有注意, 求子串复杂度太高,成功被hack, 后来瞎扯凑了个哈希刚好过题,全场过的人算我时间最长
下面给出不一定是最好,但是复杂度属于正常水平的代码

c++
#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

unsigned long long a[100005], d;
int main()
{
    char s[100005];
    int m, l;
    while(~scanf("%d %d", &m, &l))
    {
        scanf("%s", s);
        int n = strlen(s);
        d = 1;
        a[0] = s[0];
        for (int j=1; j<l; j++)
        {
            a[0] = a[0]*123+ s[j];
            d *= 123;
        }

        for (int i=1; i<=n-l; i++)
        {
            a[i] = (a[i-1] - d*s[i-1])*123 + s[i+l-1];
            //本来不优化这里复杂度是len, 改过以后是o(1)
        }

        int ans = 0;
        int cot;
        for (int i=0; i<l; i++)
        {
            cot = 0;
            for (int j=i;j+l<=n-l;j=j+l)
                if (a[j]==a[j+l])
                {
                    cot++;
                    if (cot>=m-1)
                        ans++;
                }
                else cot = 0;

        }
        printf("%d\n", ans);

    }
    return 0;

}

第五题

这是个dp的题
对于一个有a个石子的堆,可以等概率地变成1到a其中的任意一个数, 所以状态转移方程可以写成如下,因为当前转态只涉及自己和前面一个,中间又不需要记录什么数据,直接开个滚动数组就可以了,这样大大减小空间开销,注意初始条件,变量初始化,中间思路清晰还是不算坑的题
dp[cur][k] += dp[pre][j^k]/a[i];

  1. Study sister's dragon
    时间限制 1000 ms 内存限制 65536 KB
    题目描述
    Study sister plays the game coc everyday. One day, she asked Study brother to donate a dragon into her castle, but Study brother refused because the dragon cost too much.
    At last, they decide to play a rock game, and if Study brother lose the game, he would donate a dragon.
    There are several piles of rocks, and they pick some rocks from one pile alternatively. According to game theory, it is easy to tell who would win the game. So Study brother made a new rule. Before the game starting, Study brother will pick a random number of rocks(might be zero) but not all of them from each pile, and then they start play the game.
    Now Study brother wants to know his chance to win.
    As a gentleman, Study brother alway let Study sister to pick first when they play the game.

输入格式
There are several test case. The first line of each test case contains an integer n, means the number of piles. Then a line with n numbers shows the number of rocks of each pile. n <= 1000. The number of rocks in each pile is smaller than 128.

输出格式
For each test case, print on line, Study brother's probability of winning.

输入样例
2
2 2
输出样例

0.500000

hint
They may get 1,1 or 1,2 or 2,1 or 2,2,so the the probability is 0.5

c++
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>

using namespace std;
int a[1005];
double dp[2][130];
int main()
{
    int n;
    while (~scanf("%d", &n))
    {
        for (int i=0; i<n; i++)
        {
            scanf("%d", &a[i]);
        }
        int pre = 0;
        int cur = 1;
        for (int i=1; i<=128; i++)
        {
            dp[pre][i] = 0;
        }
        dp[pre][0] = 1;
        for (int i=0; i<n; i++)
        {
            for (int k=0; k<=128; k++)
            {
                dp[cur][k] = 0;
                for (int j=1; j<=a[i]; j++)
                {
                    dp[cur][k] += dp[pre][j^k]/a[i];
                }
            }
            swap(cur, pre);
        }
        printf("%.6lf\n", dp[pre][0]);

    }


    return 0;
}

第六题除了出题人自己过了,没有一个人过,据说是测试数据有问题,那就不纠结了,pass

第七题








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值