【SinGuLaRiTy-1007】 Copyright (c) SinGuLaRiTy 2017. All Rights Reserved.
测试题目
对于所有的题目:Time Limit:1s | Memory:256 MB
第一题:考试得分(score)[najboljih]
【题目描述】
某单位举办了一次考试,考试有8道题,每道题的得分不一样。选手可以随便做,但最后只统计5道题的得分。现在给出选手每道题的得分,求出他最后的得分最大是多少?
【输入】
8行,每行一个正整数X(0<=X<=150),第i个X表示第i道题的得分。
【输出】
第一行:该选手最后的得分。
第二行:按升序给出的选入计分的5道题的题号。
【样例数据】
样例输入 | 样例输出 |
20 30 50 48 33 66 0 64 |
261 3 4 5 6 8 |
【简单题解】
大水题
【STD Code】
#include<cstring> #include<iostream> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; struct node { int order; int value; }; node num[10]; int sto[10]; int cnt=1; bool cmp(node x,node y) { if(x.value<y.value) return 1; return 0; } int main() { freopen("score.in","r",stdin); freopen("score.out","w",stdout); int Ans=0; for(register int i=1;i<=8;i++) { scanf("%d",&num[i].value); num[i].order=i; } sort(num+1,num+9,cmp); for(register int i=4;i<=8;i++) { Ans+=num[i].value; sto[cnt]=num[i].order; cnt++; } printf("%d\n",Ans); sort(sto+1,sto+6); for(int i=1;i<=5;i++) { printf("%d ",sto[i]); } return 0; }
【International Edition】
The Croatian version of this contest has the following rules: “Each round of the contest consists of 8
tasks with different point values. Every contestant may solve any of the tasks they choose. However, the
contestant’s final score will be the sum of points earned on any 5 tasks such that this sum is maximized.”
Since the organizers were busy coming up with interesting problems for the contest (and translating
them), they’ve simply forgotten to solve the problem of determining the points scored by each
contestant. Now they are kindly asking you to do it for them.
Write a program that, given the number of points earned by a contestant on each task, determines the
total amount of points scored by that contestant, as well as the sorted list of the 5 problems counting
towards that score. No contestant will ever score the same amount of points on two different
problems.
INPUT
Input consists of 8 lines. Each line of input contains a single positive integer X (0 ≤ X ≤ 150), where
the number X in row i denotes the number of points earned by the contestant on problem i. All 8
numbers X will be distinct.
OUTPUT
The first line of output must contain the total amount of points scored by the contestant.
The second line of output must contain indices of the 5 problems counting towards the total score,
sorted in ascending order, separated by single spaces. Problem indices are positive integers from 1 to
8, inclusive.
SCORING
If only the first line of output (the total amount of points) is correct, the solution will be awarded 40%
of points on that test case (even if the second line of output is not present).
第二题:死胡同(deadend)[okret]
【题目描述】
Mirko学会了开车,但是他还不会在狭窄的街道上掉头。所以,他只能找一个禁止掉头的城镇开车。现在他已经拿到了一个城镇的地图。这个城镇可以看做是R*C的一个表格,每个格子要么为’X’,要么为’.’。’X’表示建筑的一部分,‘.’表示道路。你可以从当前格子往上下左右四个方向移动,当然,‘X’是不能进入的。如果从城镇的任一点出发,你都能找到一条路径回到原点,则认为该城镇没有死胡同,否则该城镇有死胡同,不适合Mirko开车。
【输入】
第一行包含两个整数R和C(3<=R,C<=10),表示城镇地图的行数和列数。
接下来有R行,每行C个字符,要么为’X’,要么为’.’。’X’表示建筑的一部分,‘.’表示道路。
至少有两个格子为‘.’,且保证所有‘.’都是联通的。
【输出】
唯一的一行,如果没有死胡同,输出0,否则输出1.
【样例数据】
样例输入 |
样例输出 |
4 3 XXX X.X X.X XXX |
1 |
【简单题解】
大水题,注意特殊情况即可。
【STD Code】
#include<cstring> #include<cstdio> #include<cstdlib> #include<cmath> #include<algorithm> #include<iostream> using namespace std; int city[20][20]; int model[20][20]; char data[20]; int X,R; int step_cnt=-1; int flag=1; void reset() { for(register int i=1;i<=X;i++) for(register int j=1;j<=R;j++) { model[i][j]=city[i][j]; } } void DFS(int x,int y) { step_cnt++; if(step_cnt>1&&(model[x+1][y]==3||model[x-1][y]==3||model[x][y+1]==3||model[x][y-1]==3)) flag=0; if(model[x][y]!=3) model[x][y]=0; if(model[x+1][y]==1)//up { DFS(x+1,y); } if(model[x-1][y]==1)//down { DFS(x-1,y); } if(model[x][y-1]==1)//left { DFS(x,y-1); } if(model[x][y+1]==1)//right { DFS(x,y+1); } } int main() { scanf("%d%d",&X,&R); for(register int i=1;i<=X;i++) { scanf("%s",data+1); for(register int j=1;j<=R;j++) { city[i][j]=(data[j]==‘X‘ ? 0 : 1); } } for(register int i=1;i<=X;i++) for(register int j=1;j<=R;j++) { if(city[i][j]!=0) { reset(); model[i][j]=3; DFS(i,j); if(flag==1) { printf("1"); return 0; } flag=1; step_cnt=-1; } } printf("0"); return 0; }
【International Edition】
Mirko has been learning to drive, but he still cannot make a U-turn in a narrow street. That’s why he
has decided to go practice in a town where U-turns are forbidden everywhere. This prohibition can be
marked by the following sign:
Mirko has soon figured out that his ideal town must not contain dead-end streets, since it is impossible
to exit such a street without a U-turn (let us assume that Mirko cannot drive in reverse either). Write a
program to analyse a town map and determine whether the town is suitable for Mirko (i.e. whether the
town has any dead-end streets).
The town map is a table with R x C cells, where each cell is a building segment (denoted by X) or a
road surface (denoted by a dot). From a road surface cell, Mirko can move to any of the surrounding
four cells (up, down, left, or right), provided that it is also a road surface (i.e. not a building).
Formally, we will determine that a town is free of dead-end streets if, starting from any road surface cell
and going in any of the possible directions, we can return to the starting cell without making a 180
degrees turn (changing our direction to the opposite one).
INPUT
The first line of input contains the positive integers R and C (3 ≤ R, C ≤ 10), the dimensions of the
town.
Each of the next R lines contains C characters, with each character either “X” or “.”. These R x C
characters represent the town map as described in the text above. At least two cells will be road
surfaces, and all road surfaces will be connected (i.e. mutually reachable).
OUTPUT
The first and only line of output must contain 0 if the town is free of dead-end streets, otherwise it
must contain 1.
第三题:最大公约数(gcd)[zadaca]
【题目描述】
Mirko的家庭作业是求两个正整数A,B的最大公约数。因为数字太大,老师提供了N个小点的数,他们的乘积为A,又提供了M个小点的数,他们的乘积为B。
Mirko想验证他的结果,于是他请你写个程序帮帮他。
如果结果超过9位,只需输出最后的9位。
【输入】
输入格式:第一行包含一个正整数N(1<=N<=1000)
第二行包含N个空格隔开的正整数,每个整数小于1000000000,它们的乘积为A。
第三行包含正整数M(1<=M<=1000)
第四行包含M个空格隔开的正整数,每个整数小于1000000000,它们的乘积为B。
【输出】
唯一的一行,表示A和B的最大公约数。如果超过9位,只需要输出最后的9位。
【样例数据】
样例输入 |
样例输出 |
3 358572 83391967 82 3 50229961 1091444 8863 |
12028 |
【简单题解】
水题,直接因数分解一遍,再查找相同的因数(用哈希),求较小值即可,对于10^9的判定应该很容易的,注意特殊情况;
【STD Code】
#include<cstdio> #include<algorithm> #define MOD 1000000000 #define ll long long using namespace std; bool h[35005]; int p[10005]; int cnt,n,m,l,w; ll ans=1; int A[10005]; int B[10005]; ll ksm(ll a,int k) { if(k==0)return 1ll; ll o=ksm(a,k/2); ll p=o*o; if(p>=MOD) { p%=MOD; w=1; } if(k&1) { p*=a; if(p>=MOD) { p%=MOD; w=1; } } return p; } void add(int *K,int a) { for(int i=1;i<=cnt;i++) { while(a%p[i]==0) { a/=p[i]; K[i]++; } } if(a>1) { p[++cnt]=a; K[cnt]++; a=1; } } int main() { //freopen("gcd.in","r",stdin); //freopen("gcd.out","w",stdout); for(int i=2;i*i<=MOD;i++) { if(!h[i]) p[++cnt]=i; for(int j=1;j<=cnt&&i*p[j]<=35000;j++) h[i*p[j]]=1; } scanf("%d",&n); for(int i=1;i<=n;i++) { int r; scanf("%d",&r); add(A,r); } scanf("%d",&m); for(int i=1;i<=m;i++) { int r; scanf("%d",&r); add(B,r); } for(int i=1;i<=cnt;i++) { ans*=ksm(p[i],min(A[i],B[i])); if(ans>=MOD) { ans%=MOD; w=1; } } if(w==1) printf("%09d",int(ans)); else printf("%d",int(ans)); }
【International Edition】
Mirko has received a homework assignment to compute the greatest common divisor of the two
positive integers A and B. Since the numbers are quite large, the teacher provided him with N smaller
integers whose product is A, and M integers with product B.
Mirko would like to verify his result, so he has asked you to write a program to solve his problem.
If the result is more than 9 digits long, output only the last 9 digits.
INPUT
The first line of input contains the positive integer N (1 ≤ N ≤ 1000).
The second line of input contains N space-separated positive integers less than 1 000 000 000, whose
product is the number A.
The third line of input contains the positive integer M (1 ≤ M ≤ 1000).
The fourth line of input contains M space-separated positive integers less than 1 000 000 000, whose
product is the number B.
OUTPUT
The first and only line of output must contain the greatest common divisor of numbers A and B. If the
result is more than 9 digits long, output only the last (least significant) 9 digits.
第四题:数对(pair)[kompici]
【题目描述】
在成功的完成了家庭作业后,Mirko无聊地写下了N个数。其中有些数对是他喜欢的,有些数对是他不喜欢的。他喜欢的数对有这样一个特征:两个数中至少有一位共同的数字,不要求他们在同一位。
帮助Mirko计算他喜欢的数对有多少?
【输入】
第一行包含正整数N(1<=N<=1000000)
接下来N行,每行包含1个正整数,在区间[1,1018],表示Mirko写下的数。没有两个数是相等的。
【输出】
唯一的一行,表示Mirko喜欢的数对有多少。
【样例数据】
样例输入 |
样例输出 |
4 32 51 123 282 |
4 |
【简单题解】
需要用到容斥原理,对于开始的10^6个数,由于本质不同的只有1024个,所以可以压缩成1024种情况,这样总的复杂度就是1024*1024了
【STD Code】
#include <cstdio> using namespace std; typedef long long LL; LL num[1<<12]; int n; LL ans; inline void Get_int(LL &Ret) { char ch; bool flag=false; for(;ch=getchar(),ch<‘0‘||ch>‘9‘;) if(ch==‘-‘) flag=true; for(Ret=ch-‘0‘;ch=getchar(),ch>=‘0‘&&ch<=‘9‘;Ret=Ret*10+ch-‘0‘); flag&&(Ret=-Ret); } int main() { scanf("%d",&n); LL tmp=0; for(int i=1;i<=n;i++) { tmp=0; Get_int(tmp); LL k=0; while(tmp>0) { LL t=tmp%10; tmp/=10; k|=(1<<t); } num[k]++; } for(int i=1;i<1024;i++) { if(num[i]==0) continue; for(int j=1;j<1024;j++) { if(i==j||num[j]==0||((i&j)==0)) continue; ans+=num[i]*num[j]; } ans+=num[i]*(num[i]-1); } printf("%lld\n",ans/2); return 0; }
【International Edition】
After successfully solving his math homework from the previous task, Mirko has become bored, so he
has made a list of N large integers. On the list there are some pairs of numbers that he likes, and some
pairs he doesn’t like.
Mirko has named the pairs that he likes pals. Two numbers are pals if they have at least one digit in
common (not necessarily in the same position).
Help Mirko count how many pairs of numbers in his list are pals.
INPUT
The first line of input contains the positive integer N (1 ≤ N ≤ 1 000 000).
Each of the next N lines contains a positive integer from the range [1, 1018], a number from Mirko’s
list. No two numbers in the list will be equal.
OUTPUT
The first and only line of output must contain the number of pairs that are pals.
第五题:N-th(N-th)[funkcija]
【题目描述】
Mirko写下了下面的函数:
int fun() { int ret = 0; for (int a = X1; a <= Y1; ++a) for (int b = X2; b <= Y2; ++b) ... for (int <N-th> = XN; <N-th> <= YN; ++<N-th>) ret = (ret + 1) % 1000000007; return ret; } |
function fun: longint; var ret: longint; a, b, ... , y, z: longint; begin ret := 0; for a := X1 to Y1 do for b := X2 to Y2 do ... for <N-th> := XN to YN do ret := (ret + 1) mod 1000000007; fun := ret; end; |
<N-th>表示第t个小写字母,每个Xi和Yi要么表示整数a(0<a<=100000),要么表示一个外层某个循环变量。例如,X3可以表示a,b或一个整数。Xi和Yi中至少有一个是整数常量。
计算函数的返回值。
【输入】
第一行包含一个正整数N(1<=N<=26)
接下来N行,第i行包含Xi和Yi,用空格隔开。如果Xi和Yi都为常量,则Xi<=Yi.
【输出】
唯一的一行,包含函数的返回值。
【样例数据】
样例输入 |
样例输出 |
3 1 2 a 3 1 b |
11 |
【简单题解】
神犇题!!巨神无比的递推!!这里面涉及到的思想需要慢慢总结。
【STD Code】
//本代码为COCI官方题解 #include <cstdio> #include <cstdlib> #include <cstring> #include <vector> using namespace std; const int MAXN = 26; const int MAXNUM = 100100; const int MOD = 1000000007; enum {ROOT, LEFT, RIGHT}; typedef long long llint; struct node { int x, y, z; llint dp[MAXNUM]; vector< node* > children; node() {} node(int _x, int _y, int _z) { x = _x, y = _y, z = _z; memset(dp, -1, sizeof dp); } llint solve(int from = 0) { llint &ret = dp[from]; if (ret != -1) return ret; ret = 0; if (z == ROOT) { for (int from = x; from <= y; ++from) ret = (ret + solve_for(from)) % MOD; } if (z == LEFT) { if (from > y) return ret; if (from < y) ret = solve(from + 1); ret = (ret + solve_for(from)) % MOD; } if (z == RIGHT) { if (from < x) return ret; if (from > x) ret = solve(from - 1); ret = (ret + solve_for(from)) % MOD; } return ret; } inline llint solve_for(int from) { llint ret = 1; for (vector< node* >::iterator it = children.begin(); it != children.end(); ++it) ret = (ret * (*it)->solve(from)) % MOD; return ret; } } nodes[MAXN]; int main(void) { int n; scanf("%d", &n); for (int i = 0; i < n; ++i) { char xi[10], yi[10]; scanf("%s %s", xi, yi); int x = atoi(xi); int y = atoi(yi); int z; if (x && y) z = ROOT; else if (y) { z = LEFT; nodes[xi[0] - ‘a‘].children.push_back(nodes + i); } else { z = RIGHT; nodes[yi[0] - ‘a‘].children.push_back(nodes + i); } nodes[i] = node(x, y, z); } llint ans = 1; for (int i = 0; i < n; ++i) if (nodes[i].z == ROOT) ans = (ans * nodes[i].solve()) % MOD; printf("%lld\n", ans); return 0; }
【International Edition】
Mirko has written the following function:
C++:
int fun() {
int ret = 0;
for (int a = X1; a <= Y1; ++a)
for (int b = X2; b <= Y2; ++b)
...
for (int <N-th> = XN; <N-th> <= YN; ++<N-th>)
ret = (ret + 1) % 1000000007;
return ret;
}
Pascal:
function fun: longint;
var
ret: longint;
a, b, ... , y, z: longint;
begin
ret := 0;
for a := X1 to Y1 do
for b := X2 to Y2 do
...
for <N-th> := XN to YN do
ret := (ret + 1) mod 1000000007;
fun := ret;
end;
<N-th> denotes the Nth lowercase letter of the English alphabet. Each Xi and Yi denotes either a
positive integer less than or equal to 100 000 or a name of a variable that some outer loop iterates over.
For example, X3 can be either a, b, or an integer literal. At least one of Xi and Yi will be an integer
literal (i.e. not a variable name) for every i.
Compute the return value of the function.
INPUT
The first line of input contains the positive integer N (1 ≤ N ≤ 26).
For the next N lines, the i
th line contains Xi and Yi, separated with a space. If Xi and Yi are both
integer literals, then Xi ≤ Yi.
OUTPUT
The first and only line of output must contain the return value of the function.
第六题:披萨店(pizza)[raspored]
【题目描述】
Mirko的披萨店在镇上很受欢迎,每个人都把披萨作为午餐。Mirko提供外送服务,他的送货速度非常快,所以送货的时间可以忽略不计。镇上每个人都有自己最喜欢的口味,所以,Mirko给每个人做的披萨需要不同的时间。他只有一个小烤炉,每次只能烤一个披萨。如果他给某个人的披萨早于那个人的午餐时间k个时间单位,那么他可以收到k单位的小费,反之,如果晚于客户的午餐时间k个时间单位,那么他将损失k单位的钱。所以,Mirko需要提前安排好每个披萨制作的次序,以保证他的小费尽量多。每个客户的午餐时间是确定的,他的披萨需要花多少时间做好也是确定的。但是,可能客户会有所改变,一旦改变,那么mirko可能需要调整他的计划。Mirko从时刻0开始制作披萨。
【输入】
第一行包含两个正整数N和C,表示镇上的居民数和改变要求的次数。
接下来N行,每行包含两个正整数Li表示居民i的午餐时间,Ti表示居民i的披萨制作好需要的时间。
接下来有C行,每行包含3个正整数:R表示居民的序号,L表示该居民新的午餐时间,T表示该居民的新口味披萨需要制作的时间。
【输出】
第一行输出包含未发生改变时,Mirko能获得的最多的小费。接下来C行,每行表示发生了改变后,Mirko能获得的最多的小费。
【样例数据】
输入样例1: 3 2 10 2 6 5 4 3 1 6 1 3 0 10 |
输入样例2: 4 2 3 2 0 3 4 3 4 1 3 0 4 1 4 5 |
输入样例3: 6 7 17 5 26 4 5 5 12 4 8 1 18 2 3 31 3 4 11 5 4 19 3 5 23 2 6 15 1 5 19 1 3 10 4 |
输出样例1: 3 2 -11 |
输出样例2: -8 -13 -18 |
输出样例3: 27 59 56 69 78 81 82 58 |
【数据规模】
1<=N,C<=200000,
0<=Li,L<=100000
1<=Ti,T<=100000,
1<=R<=N
【简单题解】
模型转化后可以发现T是无用的,只需要按照时间递增的顺序执行任务(贪心的经典模型),然后用线段树维护这个递增序的和就行了
【STD Code】
//本代码为官方题解 #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; typedef long long llint; #define MAX 200005 int N, Q; int f[ MAX ]; int T[ 2 * MAX ]; int D[ 2 * MAX ]; int I[ 2 * MAX ]; llint SolT, SolD; vector< pair< int, int > > v; struct logaritamska { llint t[ 2 * MAX ]; void update( int x, int v ) { for( int i = x + 1; i < 2 * MAX; i += i&-i ) t[i] += v; } llint query( int x, int y ) { if( x > y ) return 0; llint ret = 0; for( int i = y + 1; i; i -= i&-i ) ret += t[i]; for( int i = x; i; i -= i&-i ) ret -= t[i]; return ret; } } p, s; int pos( int idx ) { return lower_bound( v.begin(), v.end(), make_pair( -T[idx], idx ) ) - v.begin(); } void fix( int cpos, int idx, int sgn ) { SolT += sgn * llint( p.query( 0, cpos - 1 ) + 1 ) * T[idx]; SolT += sgn * s.query( cpos + 1, N + Q - 1 ); SolD += sgn * D[idx]; p.update( cpos, sgn ); s.update( cpos, sgn * T[idx] ); } int main( void ) { scanf( "%d%d", &N, &Q ); for( int i = 0; i < N; ++i ) { scanf( "%d%d", D+i, T+i ); v.push_back( make_pair( -T[i], i ) ); } for( int i = N; i < N+Q; ++i ) { scanf( "%d%d%d", I+i, D+i, T+i ); --I[i]; v.push_back( make_pair( -T[i], i ) ); } sort( v.begin(), v.end() ); for( int i = 0; i < N; ++i ) { fix( pos( i ), i, +1 ); f[i] = i; } printf( "%lld\n", SolD - SolT ); for( int i = N; i < N+Q; ++i ) { fix( pos( f[I[i]] ), f[I[i]], -1 ); fix( pos( i ), i, +1 ); f[I[i]] = i; printf( "%lld\n", SolD - SolT ); } return 0; }
【International Edition】
Mirko’s pizza place is the best one in town. It is so good that all town residents eat pizza for lunch every day. Mirko’s delivery service is so fast that the delivery time is negligible. The problem is baking the pizzas, since all residents have their own favourite topping combination, so baking pizzas for two different residents doesn’t always take the same amount of time. Mirko only has one small baking oven with a capacity of a single pizza at a time, so good scheduling is extremely important and must be
determined before the day starts.
For each of the N town residents (denoted by numbers from 1 to N) we know the baking duration for their favourite pizza (Ti), as well as the moment in the day when they plan on having lunch (Li). If a resident receives their pizza K moments before the planned lunch time, Mirko is rewarded with a tip of K kunas1. On the other hand, if the pizza is delivered K moments late (after the planned lunch time), Mirko must pay the resident K kunas (because of his timely delivery insurance policy). If the pizza is
delivered precisely on time, Mirko won’t get a tip, but he doesn’t have to pay anything either.
Mirko would like to know the maximum total tip (including all insurance payouts as negative tips) that can be earned in a day if pizzas are baked in an optimal order. Notice that Mirko can earn a negative total tip (if he has to pay out more insurance than the amount of tips he receives).
Since residents sometimes change their favourite pizza toppings, as well as their preferred lunch time, Mirko’s schedule must be adapted in order to keep earning optimal tip amounts. Write a program to compute the maximum total tip for the beginning requirements, as well as after each change.
Note: In this town, the day starts at the moment t = 0 and lasts much longer than the time needed to
bake pizzas for all residents. The schedule, including the adaptations, must be determined before the
day starts.
INPUT
The first line of input contains two positive integers N and C, the number of residents and the number
of pizza requirement changes, respectively.
Each of the next N lines contains two positive integers: Li
, the moment when resident i plans on
having lunch, and Ti
, the time needed to bake the pizza for resident i.
Each of the next C lines contains three positive integers: R (the index of a resident), L (the new
moment when resident R plans on having lunch), and T (the time needed to bake resident R’s new
favourite pizza).
Constraints:
1 ≤ N, C ≤ 200 000,
0 ≤ Li
, L ≤ 100 000,
1 ≤ Ti
, T ≤ 100 000,
1 ≤ R ≤ N.
OUTPUT
The first line of output must contain the maximum total tip for the beginning requirements of the
residents.
For each of the C changes, the output must contain an additional line of output containing the new
maximum total tip value after the change.
SCORING
In test cases worth 50% of points, the following constraint holds: 1 ≤ Ti
, T ≤ 1000.
官方题解
COCI 2011/2012 Task NAJBOLJIH 5-考试得分
Round 2, November 19th, 2011 Author: Nikola Dmitrovi?
It is possible to solve this task in various ways. Expect for the most obvious solution where one looks for the 5 wanted numbers with 5 nested loops, we could just search for the 3 numbers with minimum sum and use 3 nested loops, which simplifies the code.
min=total; //sum of all numbers
for i=1 to 6 do
for j=i+1 to 7 do
for k=j+1 to 8 do
if score[i]+score[j]+score[k] < min tada begin
min:=score[i]+score[j]+score[k];
first:=i;
second:=j;
third:=k;
end;
print (total-min);
for i=1 to 8 do
if (i != prvi) and (i != drugi) and (i != treci) then print (i);
Required skills: nested loops
Category: ad hoc
COCI 2011/2012 Task OKRET-死胡同
Round 2, November 19th, 2011 Author: Adrian Satja Kurdija
There are dead-ends inside the given city if and only if there are road surface cells that are adjacent to only one other road surface cell.
Let’s prove this. If there is a road surface cell (let’s call it A) that has only one neighbor (B), then by moving from B to A we get stuck in A, i.e. our only way out is by a 180 degrees turn, which means that dead-end exists.
If there is no such cell, than we can exit every cell using some direction other than the one by which we came in. Let’s start at some road surface cell using any direction and proceed in the following matter: leave the cell we are currently in by using direction other than the one by which we came in. Since there are finite number of free cells, we will sooner or later enter some cell which we already visited. When this happens, one of these two statements are true: either we returned to the starting point, or we can return to the starting point using the same path. In both cases it’s possible to get back to the starting point, which concludes our proof.
Described solution is very easily implemented: for each road surface cell count the number of free cells.
Required skills: matrices manipulation
Category: ad hoc
COCI 2011/2012 Task ZADA?A-最大公约数
Round 2, November 19th, 2011 Author: Ivan Katani?
Greatest common divisor of two integers can be defined as the product of their common prime factors, as following:
A = p1a1 * p2a2 * … * pnan B = p1b1 * p2b2 * … * pnbn
GCD( A, B ) = p1min(a1,b1) * p2min(a2,b2) * … * pnmin(an,bn)
where p1..pn are the prime factors and a1..an, b1..bn are corresponding exponents.
We can get the factorization of large numbers A and B by factorizing every of their given factors and summing the prime number exponents over some prime in all factorizations. Next step is computing the GCD using the expression given above. For details check out the attached code.
Alternative solution would be to find GCD of all pairs of numbers Ai, Bj and it to the result (multiply), and divide the numbers Ai, Bj with the same number to prevent adding it to the result several times (in the next iterations).
Required skills: factorization, prime numbers
Category: number theory
COCI 2011/2012 Task KOMPI?I-数对
Round 2, November 19th, 2011 Author: Adrian Satja Kurdija
First thing to notice is that for each of the input values only set of it’s digits is of importance. We are not interested in order in which digits appear or repetition of digits. Therefore, each value can be represented with sequence of 10 binary digits - 1 if that digit is present, and 0 if it isn’t.
There are at most 210 = 1024 different sequences. For each sequence, we can easily calculate how many input values yield exactly that sequence, and store these results into some array.
For each pair of sequences, it’s easy to tell if they share some digit - they do if there is a position at which both sequences have ones. If they don’t share a digit, there are no pals here. If they do, than we can form a pair of pals by choosing any value that yields the first sequence, and any value that yields the second sequence. Total number of such pairs is:
number_of_values[ sequence1 ] * number_of_values[ sequence2 ].
Finally, we must count the number of pals that have the same sequence:
number_of_values[sequence] * (number_of_values[sequence] - 1) / 2
We must go through every possible pair of sequences, so complexity is O(10242).
Required skills: binary number system
Category: ad hoc
COCI 2011/2012 Task ZADA?A-N-th
Round 2, November 19th , 2011 Author: Ivan Katani?
Greatest common divisor of two integers can be defined as the product of their common prime factors, as following:
A = p1^a1 * p2^a2 * … * pn^an
B = p1^b1 * p2^b2 * … * pn^bn
GCD( A, B ) = p1^min(a1,b1) * p2^min(a2,b2) * … * pn^min(an,bn)
where p1..pn are the prime factors and a1..an, b1..bn are corresponding exponents.
We can get the factorization of large numbers A and B by factorizing every of their given factors and summing the prime number exponents over some prime in all factorizations. Next step is computing the GCD using the expression given above. For details check out the attached code.
Alternative solution would be to find GCD of all pairs of numbers Ai, Bj and it to the result (multiply), and divide the numbers A, B with the
same number to prevent adding it to the result several times (in the next iterations).
Required skills: factorization, prime numbers
Category: number theory
COCI 2011/2012 Task FUNKCIJA-比萨店
Round 2, November 19th , 2011 Author: Goran Gaši?
First observation we can make is that loops actually represent a system of inequalities:
X1 ≤ a ≤ Y1
X2 ≤ b ≤ Y2
…
XN ≤ <N-to> ≤ YN
Solution to our problems is the number of integer solutions of the given system of inequalities modulo 1000000007.
Lets build a graph with N nodes, each node representing one inequality. From a node which represents inequality of var1 we’ll put an edge towards node of var2 if upper or lower bound of var2 is equal to the same-kind bound of var1.
This graph is disjunct union of directed rooted trees. Since variables in different trees are independent of each other, the number of solutions for inequality system is equal to the product of number of solutions for each of the trees. Let us demonstrate how to calculate the solution for
only one tree.
Let f(root) is equal to the number of solutions of the tree rooted at root. Let g(node, number) equal to the number of solutions of a subtree rooted at node, if variable bound for that node inequality is equal to number. We’ll now make the following claims
for inequality with variable lower bound (it is analog in the case of 2 variable upper bound). This algoritm has complexity of O(NM ), where M is a limit on the upper bound, which is good enough for 70% of the points. Further, we can notice that following holds (for the variable lower bound case - as before it is analog with variable upper bound): points. Further, we can notice that following holds (for the variable lower bound case - as before it is analog with variable upper bound):
Using this observation, complexity becomes O(NM) and this wins 100% points.
Required skills: dynamic programming
Category: dynamic programming, graph theory
Time: 2017-03-18