Intel Code Challenge Final Round (Div. 1 + Div. 2, Combined)題解報告

此文章可以使用目錄功能喲↑(點擊上方[+])

再一次卡在C題上,考查的居然是初中的科學知識,不過能漲一波分也是蠻開心的...

鏈接→Intel Code Challenge Final Round (Div. 1 + Div. 2, Combined)

 Problem A-Checking the Calendar

Accept: 0    Submit: 0
Time Limit: 1 second    Memory Limit : 256 megabytes

 Problem Description

You are given names of two days of the week.

Please, determine whether it is possible that during somenon-leap year the first day of some month was equal to the first day of the week you are given, while the first day ofthe next month was equal to the second day of the week you are given.Both months should belong to one year.

In this problem, we consider the Gregorian calendar to be used. The number of months in this calendar is equal to 12. The number of days in months during any non-leap year is: 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31.

Names of the days of the week are given with lowercase English letters: "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday".

 Input

The input consists of two lines, each of them containing the name of exactly one day of the week. It's guaranteed that each string in the input is from the set "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday".

 Output

Print "YES" (without quotes) if such situation is possible during some non-leap year. Otherwise, print "NO" (without quotes).

 Sample Input

monday
tuesday
sunday
sunday
saturday
tuesday

 Sample Output

NO
YES
YES

 Hint

In the second sample, one can consider February 1 and March 1 of year 2015. Both these days were Sundays.

In the third sample, one can consider July 1 and August 1 of year 2017. First of these two days is Saturday, while the second one is Tuesday.

 Problem Idea

解題思路:

【題意】

給你兩個字符串a和b,分別表示一個星期中的某一天

問是否存在這麼一種情況,一個非閏年中某個月的第一天是a,下個月的第一天是b

【類型】
簽到題,取模
【分析】

因爲是非閏年,一個月的天數只有三種情況:28、30、31

①對於只有28天的一個月,恰好是四周時間,顯然該月第一天和下個月第一天是一個星期中的同一天

②對於有30天的一個月,四周多兩天,故只要b比a多兩天就可以了

③對於有31天的一個月,同理①和②

當然,一開始要先處理星期的問題,出題人比較人性化,給出了星期一到星期日的英文寫法,不然英語水平不好的又得苦惱一會兒了

【時間複雜度&&優化】
O(1)

題目鏈接→Codeforces Problem 724A Checking the Calendar

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 100005;
const int M = 100005;
const int inf = 1000000007;
const int mod = 20160519;
map<string,int> m;
string a,b;
int main()
{
    int k;
    m["monday"]=1;
    m["tuesday"]=2;
    m["wednesday"]=3;
    m["thursday"]=4;
    m["friday"]=5;
    m["saturday"]=6;
    m["sunday"]=7;//預處理
    cin>>a>>b;
    k=(m[b]-m[a]+7)%7;
    //printf("%d\n",k);
    if(k==3||k==2||k==0)
        puts("YES");
    else
        puts("NO");
    return 0;
}

 Problem B-Batch Sort

Accept: 0    Submit: 0
Time Limit: 2 seconds    Memory Limit : 256 megabytes

 Problem Description

You are given a table consisting of n rows and m columns.

Numbers in each row form a permutation of integers from 1 to m.

You are allowed to pick two elements in one row and swap them, butno more than once for each row. Also, no more than once you are allowed to pick two columns and swap them. Thus, you are allowed to perform from 0 to n + 1 actions in total.Operations can be performed in any order.

You have to check whether it's possible to obtain the identity permutation 1, 2, ..., m in each row. In other words, check if one can perform some of the operation following the given rules and make each row sorted in increasing order.

 Input

The first line of the input contains two integers n and m (1 ≤ n, m ≤ 20) — the number of rows and the number of columns in the given table.

Each of next n lines contains m integers — elements of the table. It's guaranteed that numbers in each line form a permutation of integers from 1 to m.

 Output

If there is a way to obtain the identity permutation in each row by following the given rules, print "YES" (without quotes) in the only line of the output. Otherwise, print "NO" (without quotes).

 Sample Input

2 4
1 3 2 4
1 3 4 2
4 4
1 2 3 4
2 3 4 1
3 4 1 2
4 1 2 3
3 6
2 1 3 4 5 6
1 2 4 3 5 6
1 2 3 4 6 5

 Sample Output

YES
NO
YES

 Hint

In the first sample, one can act in the following way:

1.Swap second and third columns. Now the table is

1 2 3 4

1 4 3 2

2.In the second row, swap the second and the fourth elements. Now the table is

1 2 3 4

1 2 3 4

 Problem Idea

解題思路:

【題意】

給你一個n*m的矩陣

每行均是1~m的一個排列

現在規定:

①矩陣的每行最多隻能交換一次某兩個位置的數

②最多隻能交換一次矩形某兩列的數

問最終矩形的每一行的數是否都能夠遞增

【類型】
暴力
【分析】

如果此題沒有交換某兩列的這種操作,相信會簡單得多

因爲這樣子的話我只要判斷第i(1≤i≤n)行是不是最多隻有兩處s[i][j]!=j的位置就可以判定最終能否使得每一行的數都遞增

但是,此題多了交換某兩列的操作,當然,因爲矩陣的規模比較小,做法還是比較簡單的

首先二重循環暴力,交換第i列和第j列(1≤i<j≤m),然後再判斷在交換第i列和第j列之後,是否每一行最多隻有兩處不符合遞增的位置

需注意的是,不執行列交換的這種情況也要判一下

【時間複雜度&&優化】
O(N*M*M*M)

題目鏈接→Codeforces Problem 724B Batch Sort

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 25;
const int M = 100005;
const int inf = 1000000007;
const int mod = 20160519;
int n,m,s[N][N];
bool check()
{
    int i,j,k;
    for(i=1;i<=n;i++)
    {
        for(k=0,j=1;j<=m;j++)
            if(s[i][j]!=j)
                k++;
        if(k>2)
            return false;
    }
    return true;
}
int main()
{
    int i,j,k;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)
            scanf("%d",&s[i][j]);
    if(check())//不執行列交換的情況
    {
        puts("YES");
        return 0;
    }
    for(i=1;i<=m;i++)
        for(j=i+1;j<=m;j++)
        {
            for(k=1;k<=n;k++)
                swap(s[k][i],s[k][j]);
            if(check())
            {
                puts("YES");
                return 0;
            }
            for(k=1;k<=n;k++)
                swap(s[k][i],s[k][j]);
        }
    puts("NO");
    return 0;
}

 Problem C-Ray Tracing

Accept: 0    Submit: 0
Time Limit: 2 seconds    Memory Limit : 256 megabytes

 Problem Description

There are k sensors located in the rectangular room of size n × m meters. The i-th sensor is located at point (xi, yi). All sensors are located at distinct points strictly inside the rectangle.

Opposite corners of the room are located at points (0, 0) and (n, m). Walls of the room are parallel to coordinate axes.

At the moment 0, from the point (0, 0) the laser ray is released in the direction of point (1, 1). The ray travels with a speed ofmeters per second. Thus, the ray will reach the point (1, 1) in exactly one second after the start.

When the ray meets the wall it's reflected by the rule that the angle of incidence is equal to the angle of reflection. If the ray reaches any of the four corners, it immediately stops.

For each sensor you have to determine the first moment of time when the ray will pass through the point where this sensor is located. If the ray will never pass through this point, print  - 1 for such sensors.

 Input

The first line of the input contains three integers n, m and k (2 ≤ n, m ≤ 100 000, 1 ≤ k ≤ 100 000) — lengths of the room's walls and the number of sensors.

Each of the following k lines contains two integers xi and yi (1 ≤ xi ≤ n - 1, 1 ≤ yi ≤ m - 1) — coordinates of the sensors. It's guaranteed that no two sensors are located at the same point.

 Output

Print k integers. The i-th of them should be equal to the number of seconds when the ray first passes through the point where the i-th sensor is located, or  - 1 if this will never happen.

 Sample Input

3 3 4
1 1
1 2
2 1
2 2
3 4 6
1 1
2 1
1 2
2 2
1 3
2 3
7 4 5
1 3
2 2
5 1
5 3
4 3

 Sample Output

1
-1
-1
2
1
-1
-1
2
5
-1
13
2
9
5
-1

 Hint

In the first sample, the ray will consequently pass through the points (0, 0), (1, 1), (2, 2), (3, 3). Thus, it will stop at the point (3, 3) after 3 seconds.


In the second sample, the ray will consequently pass through the following points: (0, 0), (1, 1), (2, 2), (3, 3), (2, 4), (1, 3), (0, 2), (1, 1), (2, 0), (3, 1), (2, 2), (1, 3), (0, 4). The ray will stop at the point (0, 4) after 12 seconds. It will reflect at the points (3, 3), (2, 4), (0, 2), (2, 0) and (3, 1).


 Problem Idea

解題思路:

【題意】

m*n的矩形內部有k個點,一條光線從(0,0)出發,向(1,1)方向以米每秒運動

當光線碰到壁時會反射,碰到矩形的四個角時結束運動

問第一次經過那k個點的時間

若一個點不可達,則輸出-1

【類型】
鏡面反射,循環節
【分析】

剛開始拿到這道題,感覺除了暴力沒其他想法,但是矩形規模有點大,暴力應該會超時,所以放棄暴力的想法

那我們嘗試找找規律

當n=9,m=8時,光線的運動路線如下


當n=9,m=7時,光線的運動路線如下


經過幾種情況的嘗試,也並沒有發現有什麼竅門

這時,需要從反射這個突破口下功夫

相信大家應該知道鏡面反射中虛像的概念:


A'即爲虛像

此題就可根據虛像的性質進行處理

以樣例二爲例(n=3,m=4)


顯然,對於點(x,y),關於右壁的對稱點有兩類:

①(x+2kn,y) k=0,1,2,…

②(2(k+1)n-x,y) k=0,1,2,…

而對稱點還要判斷是否出現在上升光線上 or 下降光線上


四種情況取時間最少的就是光線到達該點的時間

四種情況分別爲:①x+2kn-y②x+2kn+y③2(k+1)n-x-y④2(k+1)n-x+y

那麼如何判斷點(x+2kn,y)在上升光線上呢?

當且僅當(x+2kn-y)%(2m)==0存在非負整數解時,在上升光線上

同理,當且僅當(x+2kn+y)%(2m)==0存在非負整數解時,在下降光線上

而要求第一次的時間,顯然要求滿足上式的最小k,那麼我們可以通過預處理循環節(2kn)%(2m),以減小時間複雜度

這題的方法解釋起來有點難,但理解了就會發現做法很簡單

以上提供的是個人的一點看法,方便大家理解,如果還有不明白之處,歡迎提出,博主會盡快予以解答

【時間複雜度&&優化】
O(max{N,M,K})

題目鏈接→Codeforces Problem 724C Ray Tracing

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
//const int N = 100005;
//const int M = 26;
const __int64 inf = 1e18;
const int mod = 20160519;
int v[200010],N,M;
__int64 solve(int x,int y)
{
    int k=(M-(x-y+M)%M)%M;
    if(v[k]!=-1)
        return 1ll*v[k]*N+x;
    return inf;
}
int main()
{
    int n,m,k,p=0,current=0,i,x,y;
    __int64 ans;
    memset(v,-1,sizeof(v));
    scanf("%d%d%d",&n,&m,&k);
    N=2*n,M=2*m;
    while(v[current]==-1)//預處理循環節
    {
        v[current]=p++;
        current=(current+N)%M;
    }
    /*for(i=0;i<N;i++)
        printf("%d ",v[i]);
    puts("");*/
    for(i=0;i<k;i++)
    {
        scanf("%d%d",&x,&y);
        ans=min(min(solve(x,M-y),solve(x,y)),min(solve(N-x,y),solve(N-x,M-y)));
        if(ans!=inf)
            printf("%I64d\n",ans);
        else
            puts("-1");
    }
    return 0;
}

 Problem D-Dense Subsequence

Accept: 0    Submit: 0
Time Limit: 2 seconds    Memory Limit : 256 megabytes

 Problem Description

You are given a string s, consisting of lowercase English letters, and the integer m.

One should choose some symbols from the given string so that any contiguous subsegment of length m has at least one selected symbol. Note that here we choose positions of symbols, not the symbols themselves.

Then one uses the chosen symbols to form a new string. All symbols from the chosen position should be used, but we are allowed to rearrange them in any order.

Formally, we choose a subsequence of indices . The selected sequence must meet the following condition: for every j such that 1 ≤ j ≤ |s| - m + 1, there must be at least one selected index that belongs to the segment [j,  j + m - 1], i.e. there should exist a k from 1 to t, such that j ≤  ≤ j + m - 1.

Then we take any permutation p of the selected indices and form a new string.

Find the lexicographically smallest string, that can be obtained using this procedure.

 Input

The first line of the input contains a single integer m (1 ≤ m ≤ 100 000).

The second line contains the string s consisting of lowercase English letters. It is guaranteed that this string is non-empty and its length doesn't exceed 100 000. It is also guaranteed that the number m doesn't exceed the length of the string s.

 Output

Print the single line containing the lexicographically smallest string, that can be obtained using the procedure described above.

 Sample Input

3
cbabc
2
abcab
3
bcabcbaccba

 Sample Output

a
aab
aaabb

 Hint

In the first sample, one can choose the subsequence {3} and form a string "a".

In the second sample, one can choose the subsequence {1, 2, 4} (symbols on this positions are 'a', 'b' and 'a') and rearrange the chosen symbols to form a string "aab".

 Problem Idea

解題思路:

【題意】

給你一個整數m和一個字符串s

現在你要從字符串s中選出一些字符

使得字符串s中任意長度爲m的連續子序列都至少包含這些字符中的一個

要求選出的這些字符排列後字典序最小

【類型】
貪心+亂搞
【分析】

要使得選出的字符排列後字典序最小,有如下幾個策略:

①假設最終選取的一系列字符中字典序最大的爲x,那麼字符串s中所有的y(字典序:y<x)都要選取

顯然 字典序: aaabb < aabb

②在滿足①的條件下,選取的字符x應儘可能少

顯然 字典序: aaabb < aaabbb

【時間複雜度&&優化】
O(26×100000)

題目鏈接→Codeforces Problem 724D Dense Subsequence

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 100005;
const int M = 26;
const int inf = 1000000007;
const int mod = 20160519;
char s[N];
int m,v[M];
bool check(int k)//判斷字符串s中任意長度爲m的連續子序列是否至少包含所選字符中的一個
{
    int i,p;
    for(i=0;s[i]!='\0'&&s[i]-'a'>k;i++);
    if(s[i]=='\0'||i>=m)
        return false;
    for(p=i+m;s[i]!='\0';i++)
    {
        if(s[i]-'a'<=k)
            p=i+m;
        if(i>=p)
            break;
    }
    if(s[i]=='\0')
        return true;
    return false;
}
int main()
{
    int i,k,p,c=0,pos;
    scanf("%d",&m);
    scanf("%s",s);
    for(i=0;s[i]!='\0';i++)
        v[s[i]-'a']++;
    for(i=0;i<26;i++)
    {
        if(!v[i])
            continue;
        if(check(i))
            break;
        while(v[i]--)
            printf("%c",i+'a');
    }
    //printf("%d\n",i);
    //printf("%c\n",i+'a');
    k=i;
    for(i=0;s[i]!='\0'&&s[i]-'a'>=k;i++)
        if(s[i]-'a'==k&&i<m)
            pos=i;
    if(s[i]=='\0'||i>=m)
        i=pos,c++,p=pos+m;
    else
        p=i+m;
    for(;s[i]!='\0';i++)
    {
        if(s[i]-'a'<k)
            p=i+m;
        if(s[i]-'a'==k)
            pos=i;
        if(i>=p)
            i=pos,c++,p=pos+m;
    }
    while(c--)
        printf("%c",k+'a');
    puts("");
    return 0;
}
菜鳥成長記
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章