XJOI 郎思轲模拟题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XJOI 郎思轲模拟题相关的知识,希望对你有一定的参考价值。

今天比赛的是郎思轲出的模拟题,比较偏数学.

全国青少年奥林匹克联赛

CCF-NOIP 2017模拟试题

 提高组(复赛)day1

                 竞赛时间:210分钟

命题:郎思轲

题目一览:

题目名称

不定长数组

台球游戏

对称的多项式

题目类型

传统型

传统型

传统型

目录

vector

billiards

poly

可执行文件名

vector

billiards

poly

输入文件名

vector.in

billiards.in

poly.in

输出文件名

vector.out

billiards.out

poly.out

每个测试点时限

1.0秒

2.0秒

2.0秒

内存限制

512MB

512MB

512MB

测试点数目

20

20

20

每个测试点分值

5

5

5

 

提交源程序文件名:

 

对于C++   语言

vector.cpp

billiards.cpp

poly.cpp

对于C     语言

vector.c

billiards.c

poly.c

对于Pascal语言

vector.pas

billiards.pas

poly.pas

 

编译选项:

对于C++   语言

-O2 -lm

-O2 -lm

-O2 -lm

对于C     语言

-O2 -lm

-O2 -lm

-O2 -lm

对于Pascal语言

-O2

-O2

-O2

 

 

注意事项:

1.文件名(程序名和输入输出文件名)必须使用英文小写。

2.除非特殊说明,结果比较方式均为忽略行末空格及文末回车的全文比较。

3.C/C++中函数main()的返回值类型必须是int,程序正常结束时的返回值必须是0

 

 

 

1. 不定长数组

vector

【问题描述】

 Description

 

 小A是一个C++初学者,最近他学会了不定长数组vector的使用方法,于是他很兴奋,就把他的好多文件存到了好多vector中。

最终小A得到了nvector,每个vector都不是空的,每个vector的类型都为字符类型char,一个vector代表小A的一个文件;由于小A只喜欢简洁的英文小写字母,因此他的文件中仅包含英文小写字母。

   接下来小A发现他每次只能对一个vector v[i] 进行这一些操作:

l v[i].push_back(ch) vector v[i]后添加一个字符ch

l v[i].pop_back() vector v[i]删除一个字符

l v[i][j]=ch vector v[i]的第j+1个字符修改为ch

现在A觉得这么多不同的文件看起来太杂乱了,因此他想对一些文件进行修改,从而使得所有的文件都相同;他想知道他最少要做几次操作能使所有的vector均相同(可以把vector修改为空,vector的长度也没有上限),请你帮他计算这个结果。

在修改文件之前,小A还想知道把任意两个vector修改为相同需要的操作数(每一次操作你可以任选一个vector进行)。设vector[i]vector[j]修改为相同需要的操作数,你只需要回答

的值。

 

注:如果你对C++或者不定长数组不熟悉,你只需对题意有大致理解即可,这并不会影响解题。

 

【输入格式】

 Input

   从文件vector.in中读取数据;

输入文件第一行一个正整数n,表示vector的个数;

接下来n行,第i行一个仅包含英文小写字母的字符串,第j个字符表示vector[i]的第j个字符;

最后一行为两个01的数k1,k2,含义见输出格式。

由于输入文件可能比较大,建议C++选手不要使用过慢的读入方式。

【输出格式】

 Output

输出到文件vector.out中;

输出共k1+k2行;

k1=1,输出一行,为上文所述的        的值;

接下来,k2=1,输出一行,即为使所有的vector均相同的最少操作次数。

【输入样例1

 Sample Input #1

3

he

she

him

1 1

 

【输出样例1

 Sample Output #1

8

5

 

【输入输出样例1说明】

在这个样例中,你两个询问都需要回答。

对于第一个询问,可以知道=2,操作方案为:

step1v[1][1]=i,操作vector[1]表示的串为“hi”

step2v[i].pop_back(),操作vector[2]表示的串也为“hi”

 可以知道2步是最少的方案。

以此类推可计算出=3=3,因此答案为2+3+3=8

对于第二个询问,可以把所有的字符串均改为“hi”;

此时答案为1+3+1=5,可以知道5为最优解。

 

 

 

【输入样例2

 Sample Input #2

10

also

rate

rateg

d

edee

edge

lae

reai

aslie

ead

0 1

 

【输出样例2

 Sample Output #2

29

 

【输入输出样例3、输入输出样例4

见选手文件下的vector3.in/vector3.ansvector4.in/vector4.ans

其中vector3.in数据范围同第3个测试点,vector4.in数据范围同第16个测试点。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

【数据范围与约定】

l 对于100%的数据,n≥2,不存在空字符串

测试点编号

n

 len

maxlen

k1

k2

1

≤10

≤10

≤5

 

1

 

1

2

3

=100

=500

=5

4

5

=300

=30000

=100

 

 

1

 

 

0

6

≤1000

7

≤5000

≤10000

≤100

8

≤10000

9

≤100000

≤1000000

≤1000000

10

11

=300

=30000

=100

 

0

 

1

12

≤1000

≤1000

≤1000

13

14

≤100000

≤1000000

≤1000000

15

16

 

 

≤100000

 

 

≤1000000

 

 

≤1000000

 

 

1

 

 

1

17

18

19

20

 

注:表示所有vector的元素个数之和,maxlen表示所有vector中最大的元素个数。

 

 

 

 

 

 

 

2. 台球游戏

billiards

【问题描述】

 Description

最近小B迷上了台球游戏,这个游戏在一张矩形球桌上进行,基本规则是将球打进球桌边缘上的球洞就会得分;为了让题目更有趣,在本题中我们认为球桌大小、球洞位置和球洞个数是不确定的,但保证球桌的四角均有球洞,在球桌长边上的两个相邻球洞距离都相等,短边上的两个相邻球洞距离也都相等。

我们记球桌长边为n,短边为m,长边上的两个相邻球洞距离为,长边上的两个相邻球洞距离为,下图表示了n=8m=6=4=2时的球桌的形态 (黑点表示球洞)

 

 

 

 

为了表示方便,我们把所有球洞进行标号:先将矩形下边界的球洞从左上角至右上角分别标号为到,然后同样将下边界的球洞标为到;最后若,将左边界、右边界除角上的球洞从上到下依次标号为到,到,你可以参照上图来帮助理解标号方式。

现在,球桌左上角有一只台球(注意:虽然球桌左上角一定有球洞,但开始时球并不会进入这个洞),这只台球会沿一定角度射出,碰到边缘会反弹(反弹时入射角等于反射角),你可以认为台球的轨迹不会弯曲,但台球碰到边缘k(开始时在左上角不算在内)后会立即停下,B想知道,对于给定的n,m,  ,  ,k和刚开始射出的角度,台球最终会进入哪个洞。

 

 

 

 

【输入格式】

 Input

   从文件billiards.in中读取数据;

第一行一个整数T表示数据组数;

接下来T行,每行7个正整数n,m,  ,  ,a,b,k,其中n,m,  ,  ,k的含义为题目描述所述,a,b表示台球初始射出的轨迹同的夹角,记该夹角为,则。

 

【输出格式】

 Output

   输出到文件billiards.out中;

输出T行,对于每个数据输出台球最终掉进的球洞编号以及球碰到边缘次数(开始时在左上角不算在内);若直到台球停下球还没有进洞,则输出-1。

 

【输入样例1

 Sample Input #1

3

8 6 4 2 1 1 2

8 6 4 2 1 1 1

9 5 3 5 1 1 20

 

【输出样例1

 Sample Output #1

D1 1

-1

B1 3

 

【输入输出样例1说明】

对于第一、二个数据,球桌形态及台球轨迹如下左图

 

 

 

 

根据上左图可以看出,第一个数据台球反弹1次进入了球洞,而第二个数据台球撞击一次后停了下来而没有进洞;

根据上右图可以看出,第三个数据台球反弹3次后进了球洞。

 

【输入输出样例2、输入输出样例3

见选手文件下的billiards2.in/billiards2.ansbilliards3.in/billiards3.ans

其中billiards2.in数据范围同第6个测试点,billiards3.in数据范围同第16个测试点。

 

【数据范围与约定】

l 对于100%的数据,,,mn, 保证a,b互质。

测试点编号

n,m

a,b

k

T

p

1

 

≤10

 

=1

=1

 

 

≤10

 

 

1

2

≤2

3

≤10

4

≤100

≤100

5

≤1000

≤1000

 

≤1000

6

≤10000

≤10000

 

 

 

 

 

≤50

 

 

0

7

 

 

 

 

 

 

 

8

 

≤100000

9

10

 

=1

11

 

 

 

 

 

 

 

1

12

13

 

 

 

14

15

16

 

 

≤100000

 

 

0

17

18

19

20

:当,p=1,否则p=0。

 

 

3. 对称的多项式

poly

【问题描述】

 Description

小C现在有一个数n和一个系数均在模n+1意义下的次数界为n

的多项式,但小C并不喜欢这个多项式,因为这个多项式

并不是对称的,而小C希望对这个多项式进行变形,成为另一个系数均在模p意义下的对称的多项式;

C的变形方式如下:

变形得到的多项式                               ,n=4,原多项式f(x)=3+2+x+4,g(x)=((3+4+2) mod 5)+((2+1+2) mod 5)+((2+1+2) mod 5)x+((3+4+2) mod 5)=4+4

现在小C给了你原多项式f(x),请你帮他转成对称的多项式g(x)

C还发现了一个性质:给出多项式,能求出x1n时的多项式在模n+1意义下的值,而给出这些值也能唯一确定一个系数在模域下的次数界为n的多项式,因此他决定给你原多项式x1nn个值,而你只要告诉他答案多项式分别在x1n时模n+1意义下的值就可以了。

 

 

【输入格式】

 Input

   从文件poly.in中读取数据;

第一行一个正整数n,,题目描述中已经解释过n的含义;

接下来n个整数,第i个整数表示当xi时原多项式f(x)在模n+1意义下的值f(i)

 

 

【输出格式】

 Output

   输出到文件poly.out中;

输出一行,n个整数,第i个整数表示当xi时答案多项式g(x)在模n+1意义下的值g(i),注意0≤g(i)≤n

【输入样例1

 Sample Input #1

4

0 3 1 2

 

 

【输出样例1

 Sample Output #1

3 1 2 0

 

 

【输入输出样例1说明】

该样例对应于题目描述中举的例子。

 

 

【输入样例2

 Sample Input #2

6

1 2 1 2 1 2

 

 

【输出样例2

 Sample Output #2

0 3 6 6 4 0

 

 

【输入输出样例3、输入输出样例4

见选手文件下的poly3.in/poly3.anspoly4.in/poly4.ans

其中poly3.in数据范围同第4个测试点,poly4.in数据范围同第11个测试点。

 

 

【数据范围与约定】

l 对于100%的数据,0≤ f(i)≤ n

测试点编号

n

测试点编号

n

1

=6

11

=4000

2

=16

12

3

=22

13

 

 

=49998

4

=100

14

5

=232

15

6

=250

16

7

=996

17

8

 

=2332

18

=100002

9

19

=500008

10

20

比赛时只做了前两题

第一题是一个暴力统计,没什么好讲

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010,LEN=1000100;
vector<char>s[N];
char b[LEN];
int n,maxlen,ch[LEN][26],len[N],k1,k2,tot[LEN],righ[LEN],rig[LEN];
ll calc1(){
    ll res=0;
    for (int i=1; i<=n; i++){
        for (int j=0; j<len[i]; j++) res+=n-ch[j][s[i][j]-a];
        res+=tot[len[i]];
    }
    return res>>1;
}
ll calc2(){
    ll res=tot[0],re=0;
    for (int i=0; i<maxlen; i++){
        re+=n-ch[i][righ[i]];
        res=min(res,re+tot[i+1]);
    }
    return res;
}
int main(){
    //freopen("vector3.in","r",stdin);
    //freopen("A.out","w",stdout);
    scanf("%d",&n);
    for (int i=1; i<=n; i++){
        scanf("%s",b);
        for (len[i]=0; b[len[i]]; len[i]++){
            s[i].push_back(b[len[i]]);
            if (++ch[len[i]][b[len[i]]-a]>rig[len[i]]){
                rig[len[i]]=ch[len[i]][b[len[i]]-a];
                righ[len[i]]=b[len[i]]-a;
            }
            tot[len[i]]++;
        }
        maxlen=max(maxlen,len[i]);
    }
    for (int i=maxlen-2; i>=0; i--) tot[i]+=tot[i+1];
    scanf("%d%d",&k1,&k2);
    if (k1) printf("%lld\\n",calc1()); 
    if (k2) printf("%lld\\n",calc2());
    return 0;
}

第二题需要每弹一次把地图展开,因为会爆longlong所以用__int128水过

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF=1e18;
ll n,m,n0,m0,a,b,k,zq1,zq2,ind1,ind2;
char ch1,ch2;
int t;
long double p=1;
void solvep0(){
    ll A=a*m,B=n0*b,ceng=B/__gcd(A,B),len=(ll)p*A*ceng/b;
    zq1=(len%n==0?len/n-1:len/n),ind1=len%n/n0;
    if (ind1==0&&zq1%2==0) ind1=n/n0;   
    if (ind1&&(zq1&1)) ind1=n/n0-ind1;
    zq1+=ceng-1;
    ch1=ceng&1?B:A;    
}
void solvep1(){
    ll A=b*n,B=m0*a,ceng=B/__gcd(A,B),len=(ll)p*A*ceng/a;
    zq2=(len%m==0?len/m-1:len/m),ind2=len%m/m0;
    if (ind2==0&&zq2%2==0) ind2=m/m0;
    if (ind2&&(zq2&1)) ind2=m/m0-ind2;
    zq2+=ceng-1;
    ch2=ceng&1?D:C;
}
int main(){
    //freopen("billiards3.in","r",stdin);
    //freopen("B.out","w",stdout);
    scanf("%d",&t);
    while (t--){
        scanf("%lld%lld%lld%lld%lld%lld%lld",&n,&m,&n0,&m0,&a,&b,&k);
        if (m0==m){
            solvep0(); 
            if (zq1<k) printf("%c%lld %lld\\n",ch1,ind1,zq1); else puts("-1");
        }else{
            solvep0();
            solvep1();
            if (zq1<=zq2&&zq1<k) printf("%c%lld %lld\\n",ch1,ind1,zq1);
            else if (zq2<zq1&&zq2<k) printf("%c%lld %lld\\n",ch2,ind2-1,zq2);
            else puts("-1");
        }
    }
}

第三题是一个奇妙的变换

技术分享

#include<bits/stdc++.h>
using namespace std;
const int N=500009;
int n,f[N],p;
inline int pow(int x,int y){
    int res=1;
    while (y){
        if (y&1) res=1ll*res*x%(n+1);
        x=1ll*x*x%(n+1);
        y>>=1;
    }
    return res;
}
int main(){
    scanf("%d",&n);
    for (int i=1; i<=n; i++) scanf("%d",&f[i]);
    printf("%d ",(f[1]+f[1]+2*n)%(n+1));
    for (int i=2; i<=n; i++){
        p=pow(i,n-1);
        printf("%d ",(f[i]+1ll*p*f[p]%(n+1))%(n+1));
    }
}

以上是关于XJOI 郎思轲模拟题的主要内容,如果未能解决你的问题,请参考以下文章

XJOI2016提高组模拟题一 排队

xjoi2016模拟题1

XJOI模拟训练22

xjoi省选模拟赛_14

XJOI contest 1592

XJOI CSP-S2 2019开放模拟训练题1 赛后总结