测试题---共4题。时限1s,内存128M。

distinct

【问题描述】

陶陶为了给一道平面几何题出数据,需要产生 N 个点(x[i],y[i])。

已知x,y是由伪随机函数顺序产生,即:X[i+1] = (X[i]*Ax+Bx+i) mod Cx (X[1], Ax,Bx,Cx 是事先给定的)

Y[i+1] = (Y[i]*Ay+By+i) mod Cy (Y[1], Ay,By,Cy 是事先给定的)这样,就可以快速连续产生很多点坐标(X[i], Y[i])。不幸的是,这样产生的点有可能有相同的,虽然这种几率很少,但严谨的陶陶不允许这种事发生。

陶陶要求你帮助他解决最少要产生前多少项时,正好有 N 个不相同的点。输入格式:第一行。一个整数 N .第二行:4个整数 X[1]、 Ax、Bx、Cx .第三行:4个整数 Y[1]、 Ay、By、Cy .输出格式:一个整数 M 。表示最少要连续产生 M 个点,正好有 N 个不相同的点。数据保证有答案。

数据范围:1<=N<=1,000,000, 其它所有数据都在[1...1,000,000,000]范围内。

输入样例(distinct.in):

21

2 4 3 6

5 2 3 13

输出样例(distinct.out):

24

 

//我打了四段代码可是只有一段AC~~~其他三段都是50分30分TLE,也许这道题就是针对这个出的吧。

(100'AC)(hashtable1)C++code1
1 //#include<cstdio>
2  #include<fstream>
3  using namespace std;
4 ifstream cin("distinct.in");
5 ofstream cout("distinct.out");
6  long long n;
7  long long hash[4000038];
8  long long xx[4000038],yy[4000038];
9  long long x,ax,bx,cx;
10  long long y,ay,by,cy;
11  long long tot;
12  int main()
13 {
14 cin>>n;
15 cin>>x>>ax>>bx>>cx;
16 cin>>y>>ay>>by>>cy;
17 long long sum=1,i=1;
18 while (sum<n)
19 {
20 i++;
21 x=(x*ax+bx+i-1)%cx;
22 y=(y*ay+by+i-1)%cy;
23 long long t=(x*1321+y*1417)%4000037;
24 while (hash[t]!=0&&(xx[hash[t]]!=x||yy[hash[t]]!=y)) t=(t+9973)%4000037;
25 if (hash[t])
26 {
27 if (xx[t]==x&&yy[t]==y) continue;
28 }
29 else
30 {
31 tot++;
32 xx[tot]=x;
33 yy[tot]=y;
34 hash[t]=tot;
35 sum++;
36 }
37 }
38 cout<<i<<endl;;
39 return 0;
40 }
41  

 

(50'TLE)(BST)C++code2
1 #include<fstream>
2 #include<cstdlib>
3 #include<cstring>
4  #define maxn 3000010
5  using namespace std;
6 ifstream cin("distinct.in");
7 ofstream cout("distinct.out");
8 int n,tot,sum;
9 struct node
10 {
11 long long x,y,l,r;
12 }f[maxn];
13 int ax,bx,cx;
14 int ay,by,cy;
15 int main()
16 {
17 cin>>n;
18 cin>>f[1].x>>ax>>bx>>cx;
19 cin>>f[1].y>>ay>>by>>cy;
20 int i=1;
21 sum=1;
22 while (sum<n)
23 {
24 i++;
25 f[i].x=(f[i-1].x*ax+bx+i-1)%cx;
26 f[i].y=(f[i-1].y*ay+by+i-1)%cy;
27 int s=1;
28 while (1)
29 {
30 if (f[i].x<f[s].x)
31 {
32 if (!f[s].l) {f[s].l=i;sum++;break;}
33 else {s=f[s].l;continue;}
34 }
35 if (f[i].x>f[s].x)
36 {
37 if (!f[s].r) {f[s].r=i;sum++;break;}
38 else {s=f[s].r;continue;}
39 }
40 if (f[i].x==f[s].x)
41 {
42 if (f[i].y<f[s].y)
43 {
44 if (!f[s].l) {f[s].l=i;sum++;break;}
45 else {s=f[s].l;continue;}
46 }
47 if (f[i].y>f[s].y)
48 {
49 if (!f[s].r) {f[s].r=i;sum++;break;}
50 else {s=f[s].r;continue;}
51 }
52 if (f[i].y==f[s].y) break;
53 }
54
55 }
56 }
57 cout<<i<<endl;
58 return 0;
59 }
60

 

(30'TLE)(hashtable2)C++code3
1 #include<fstream>
2 #include<cstdio>
3 #include<cstdlib>
4 #include<cstring>
5 #define maxn 1000010
6 using namespace std;
7 ifstream cin("distinct.in");
8 ofstream cout("distinct.out");
9 long long n,tot,sum;
10 long long x,y;
11 long long ax,bx,cx;
12 long long ay,by,cy;
13 struct node
14 {
15 long long x,y;
16 node *next;
17 }*a[16777216];
18 bool hash(int x,int y)
19 {
20 long long tmpx=x,tmpy=y,k=0,h=0,r=0;
21 while (tmpx)
22 {
23 h=((h<<6)+((tmpx ^ y) & 255))&16777215;
24 tmpx=tmpx>>5;
25 }
26 while (tmpy)
27 {
28 r=((r<<6)+((tmpy ^ x) & 255))&16777215;
29 tmpy=tmpy>>5;
30 }
31 h=(h+r)&16777215;
32 node *t=a[h];
33 while (t!=NULL)
34 {
35 if (t->x==x&&t->y==y) return false;
36 t=t->next;
37 }
38 // t=malloc(sizeof(node));
39 t=new(node);
40 t->x=x;
41 t->y=y;
42 t->next=a[h];
43 a[h]=t;
44 return true;
45 }
46
47 int main()
48 {
49 // freopen("distinct.in","r",stdin);
50 // freopen("distinct.out","w",stdout);
51 // scanf("%d\n",&n);
52 // scanf("%d%d%d%d\n",&x,&ax,&bx,&cx);
53 // scanf("%d%d%d%d\n",&y,&ay,&by,&cy);
54 cin>>n;
55 cin>>x>>ax>>bx>>cx;
56 cin>>y>>ay>>by>>cy;
57 long long i=1;
58 sum=1;
59 hash(x,y);
60 while (sum<n)
61 {
62 i++;
63 x=(x*ax+bx+i-1)%cx;
64 y=(y*ay+by+i-1)%cy;
65 if (hash(x,y)) sum++;
66 }
67 // printf("%d\n",i);
68 cout<<i<<endl;
69 return 0;
70 }
71

 

 

(30'TLE)(treap)C++code4
1 #include<fstream>
2 #include<cstdlib>
3 #include<cstring>
4 #define maxn 2000010
5 using namespace std;
6 ifstream cin("distinct.in");
7 ofstream cout("distinct.out");
8 int n,tot=0,sum=0;
9 struct node
10 {
11 long long x,y;
12 int pri;
13 node* ch[2];
14 }*root,tree[maxn];
15 long long x,ax,bx,cx;
16 long long y,ay,by,cy;
17 node *New_node(int x,int y)
18 {
19 node *p=&tree[++tot];
20 p->x=x;
21 p->y=y;
22 p->pri=rand()*rand();
23 p->ch[0]=p->ch[1]=NULL;
24 return p;
25 }
26 void rotate(node* &x,int t)
27 {
28 node *y=x->ch[t];
29 x->ch[t]=y->ch[!t];
30 y->ch[!t]=x;
31 x=y;
32 }
33 void insert(node* &now,node* new_node,int &sum)
34 {
35 if (now==NULL)
36 {
37 sum++;
38 now=new_node;
39 return;
40 }
41 int t;
42 if (now->x!=new_node->x)
43 {
44 t=now->x<new_node->x;
45 }
46 else
47 {
48 if (now->y!=new_node->y) t=now->y<new_node->y;
49 else
50 if (now->y==new_node->y) return;
51 }
52 insert(now->ch[t],new_node,sum);
53 if (now->ch[t]->pri>now->pri) rotate(now,t);
54 }
55 int main()
56 {
57 srand(time(NULL));
58 cin>>n;
59 cin>>x>>ax>>bx>>cx;
60 cin>>y>>ay>>by>>cy;
61 int i=1,sum=1;
62 root=New_node(x,y);
63 while (sum<n)
64 {
65 i++;
66 x=(x*ax+bx+i-1)%cx;
67 y=(y*ay+by+i-1)%cy;
68 insert(root,New_node(x,y),sum);
69 }
70 cout<<i<<endl;
71 return 0;
72 }
73

 

Allbarns

农民约翰打算建一个新的矩形谷仓。但是,矩形谷仓的4个角落不能在落在软土路基上,只能落在一些固定点上。

现在,他已经找到地面上有N(4 <= N <= 1,000)个点,角落只可以落在这些点上。

他想知道依次每加多一个点,可以建立新谷仓的方法数量,请你帮助他找到答案。

输入格式:

第1行:一个整数,N第2行至N +1行:每行有两个被空格分隔的整数的x,y,作为一个点的坐标。所有的x,y都不会超过16,000。所有点都是不同的。输出格式:共 N 行:每行表示当前可以建立的新的谷仓的数目。

样例输入(allbarns.in):

8

1 2

1 -2

2 1

2 -1

-1 2

-1 -2

-2 1

-2 -1

样例输出(allbarns.out):

0

0

0

0

0

1

3

6

样例解释:最后的答案是(1,2,6,5),(1,3,6,8),(1,4,6,7),(2,3,5,8),(2,4,5,7),(3,4,8,7)

 

#include<cstdio>
int n,ans;
int ax[1010],ay[1010];
int xx[1000010],yy[1000010],len[1000010],num[1000010];
int hash[4000040];
int count;
int main()
{
    freopen("allbarns.in","r",stdin);
    freopen("allbarns.out","w",stdout);
    scanf("%d\n",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%d%d\n",&ax[i],&ay[i]);
        for (int j=1;j<=i;j++)
        {
            int x=ax[i]+ax[j];
            int y=ay[i]+ay[j];
            int l=(ax[i]-ax[j])*(ax[i]-ax[j])+(ay[i]-ay[j])*(ay[i]-ay[j]);
            int p=(x*1321+y*1171+l*1091)%4000037;
            while (hash[p]&&(len[hash[p]]!=l||xx[hash[p]]!=x||yy[hash[p]]!=y))
            p=(p+9973)%4000037;
            if (!hash[p])
            {
                         count++;
                         xx[count]=x;
                         yy[count]=y;
                         len[count]=l;
                         num[count]=1;
                         hash[p]=count;
            }
            else{ans+=num[hash[p]];num[hash[p]]++;}
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

cubes

FJ和Best用 N (1 <= N <= 30,000)块相同的小立方块玩游戏,小方块编号为1..N。开始时,小方块都单独分开的,每个看成一个柱子,即有 N 柱子。

FJ要Best做 P(1 <= P <= 100,000) 个操作,操作有两种类型:(1) FJ要求Best把X号方块所在的柱子放到Y号所在的柱子上面,成一个新柱子。

(2)FJ要求Best计算X号方块所在柱子,它下面有多少个小方块。

请编个程序,帮助Bet计算。输入格式:*第一行:一个整数 P*第2..P+1行:第i+1行表示第i个FJ要求的合法操作。

如果这行以'M'开头,后面有两个整数 X,y 表示要进入(1)操作。 如果这行以'C'开头,后面有一个整数 X,表示要求计算X所在柱子下面的方块个数。

注:所有操作都是合法的。N 并没有出现在输入文件中。输出格式:依次要求计算的值,每次一行。

输入样例 (cubes.in):

6 | 6个操作

M 1 6 | 1,6 / 2 / 3 / 4 / 5 把1放在6上面。

C 1 | 输出:1

M 2 4 | 1,6 / 2,4 / 3 / 5

M 2 6 | 2,4,1,6 / 3 / 5

C 3 | 输出 :0

C 4 | 输出: 2

输出样例(cubes.out)

1

0

2

 

#include<cstdio>
#include<cstdlib>
#define maxn 30010 
int p;
int father[maxn];
int before[maxn];
int tot[maxn];
char c;
int get(int x)
{
    if (father[x]==x) return x;
    int t=get(father[x]);
    before[x]+=before[father[x]];
    father[x]=t;
    return father[x];
}
void make(int x,int y)
{
     int a=get(x);
     int b=get(y);
     if (a!=b)
     {
              father[a]=b;
              before[a]+=tot[b];
              tot[b]+=tot[a];
     }
}
int main()
{
    freopen("cubes.in","r",stdin);
    freopen("cubes.out","w",stdout);
    scanf("%d\n",&p);
    for (int i=1;i<maxn;i++)
    {
        father[i]=i;
        tot[i]=1;
    }
    int x,y;
    for (int i=1;i<=p;i++)
    {
        scanf("%c",&c);
        if (c=='M')
        {
                   scanf("%d%d\n",&x,&y);
                   make(x,y);
                   continue;
        }
        if (c=='C')
        {
                   scanf("%d\n",&x);
                   get(x);
                   printf("%d\n",before[x]);
        }
    }
}

 

 

friend

【问题描述】

有一个镇有N个居民。当然其中有许多人是朋友的关系。根据有名的谚语:“我朋友的朋友也是我的朋友”,所以如果A和B是朋友,B和C是朋友,

那么A和C也是朋友。你的任务是算出在这个镇中最大的朋友集团为多少人。

【输入文件】

输入文件的第一行有2个正整数 N 和 M 。N代表镇上居民的数目(1 <= N <= 30000 ),

M 代表这些居民中朋友关系的数目( 0 <= M <= 30000)。接下来的M行每行有2个整数A,B( 1 <= A,B <= N , A不等于B),

代表A,B为朋友关系。这M行中可能有的会重复出现。

【输出文件】输出文件仅一行,在这个镇中最大的朋友集团为多少人。

【输入样例】

10 12

1 2

3 1

3 4

5 4

3 5

4 6

5 2

2 1

7 10

1 2

9 10

8 9

【输出样例】

6

 

#include<cstdio>
#include<cstring>
#include<cstdlib>
int n,m;
int father[30010];
int sum[30010];
int ans;
int get(int x)
{
    if (father[x]==x) return x;
    father[x]=get(father[x]);
    return father[x];
}
void make(int x,int y)
{
     int a=get(x);
     int b=get(y);
     if (a!=b) father[a]=b;
}
int main()
{
    freopen("friend.in","r",stdin);
    freopen("friend.out","w",stdout);
    scanf("%d%d\n",&n,&m);
    for (int i=1;i<=n;i++) father[i]=i;
    int a,b;
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d\n",&a,&b);
        make(a,b);
    }
    for (int i=1;i<=n;i++)
    {
        int t=get(i);
        sum[t]++;
        if (sum[t]>ans) ans=sum[t];
    }
    printf("%d\n",ans);
    return 0;
}