程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> 第九周周賽——周賽兼組隊賽第一場題解(出自HDU5443,本oj,HDU 5667,poj1742,codeforces 664A,BUNOJ 28199)

第九周周賽——周賽兼組隊賽第一場題解(出自HDU5443,本oj,HDU 5667,poj1742,codeforces 664A,BUNOJ 28199)

編輯:關於C

A題:

jsp?pid=1704">A題題目鏈接

題目描述:

The Water Problem

TimeLimit:1000MSMemoryLimit:131072KB 64-bit integer IO format:%I64d
Problem Description

In Land waterless, water is a very limited resource. People always fight for the biggest source of water. Given a sequence of water sources with a1,a2,...,an representing the size of the water source. Given a set of queries each containing 2 integers l and r, please find out the biggest water source between al and ar.

Input

First you are given an integer T (T <= 10) indicating the number of test cases. For each test case, there is a number n (0 <= n <= 1000) on a line representing the number of water sources.n integers follow, respectivelya1,a2,...,an, and each integer is in {1, . . . , 10^6}. On the next line, there is a number q (0 <= q <= 1000) representing the number of queries. After that, there will be q lines with two integers l and r (1 <= l <= r <= n) indicating the range of which you should find out the biggest water source.

Output For each query, output an integer representing the size of the biggest water source. SampleInput
3
1
100
1
1 1
5
1 2 3 4 5
5
1 2
1 3
2 4
3 4
3 5
3
1 999999 1
4
1 1
1 2
2 3
3 3
SampleOutput
100
2
3
4
4
5
1
999999
999999
1
題意:

給定T組測試數據,每組測試數據的第一行數是n,表示有n個數字,接下來的一行為n個數字,然後再接下來的一行是一個數q,表

示有q組詢問,每組詢問占一行,有兩個數l,r,然後對於每一組詢問輸出在第l個到第r個數中(包含邊界)最大的數。

解析:

由於n和q的范圍都不大,均小於1000,因此暴力求解即可。時間復雜度為O(n*q),注意當數據范圍較大的時候,可用線段樹求解,

總體的時間復雜度為O(q * logn).

完整代碼實現:

#include
#include
using namespace std;
const int MAX_N = (int)1e3 + 10;
int a[MAX_N];
int main(){
    int T,n,q,x,y;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i = 1;i <= n;++i){
            scanf("%d",&a[i]);
        }
        scanf("%d",&q);
        while(q--){
            scanf("%d %d",&x,&y);
            int ans = 0;
            for(int i = x;i <= y;++i){
                ans = max(a[i],ans);
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}
B題:

B題題目鏈接

題目描述:

T^T找數字

TimeLimit:1000MSMemoryLimit:256MB 64-bit integer IO format:%I64d
Problem Description

有一天,T^T來到了師大比賽,看上了師大的ACMer小彩,於是他就跑上去想跟人家搭讪,可是呢,這時候,小彩遇到了一個問題,小彩說,你要是幫我解決了這個

問題,我就把我的手機號給你,T^T一聽,頓時樂了起來,這不是我的強項嘛,於是就讓小彩說了:

給定整數a1,a2,....,an,判斷是否可以從中選出若干數(取數的數目 > 0),使它們的和恰好為k

Input

輸入有多組數據,輸入的第一行有兩個數,分別為n,k(1 <= n <= 20,-10^8 <= k <= 10^8,不考慮k = 0的情況);

第二行是n個數,分別是a1,a2,a3,...,an(-10^8 <= ai <= 10^8)


Output

能找到這樣的若干個數的和為k(由於oj無法特判,因此輸入保證只有一組這樣的數),則輸出YES,並且按照順序輸出這些數,否則的話,輸出NO


SampleInput
4 13
1 2 4 7
4 15
1 2 4 7
SampleOutput
YES
2 4 7
NO
解析:

B題是我從《挑戰程序設計競賽》》上看到的題目,並對其進行了簡單的改編。因此也就沒有放入比較強的測試數據(其實是我

懶O(∩_∩)O),只是讓大家感受一下入門的搜索算法。

廢話少說,題目是說要從給定的n個數中,是否能夠找出若干個數(注意這若干個數顯然是可以不連續的),使得這些數的和為

k,若能,則輸出YES,並且按順序輸出這些數;若不能,則輸出NO。

我們用一個臨時變量sum來標記這些數的和,顯然,一開始的時候,sum的值為0.然後我們考慮給定的這n個數,對於每個

數,只有兩種狀態,要麼取這個數,要麼不取,而這道題n的數據范圍是n<=20,因此我們可以考慮遍歷所有的狀態,而將這些狀態

用圖形描述出來則是下圖:

\

從上圖我們可知,所有狀態組成了一棵滿二叉樹,因此我們可以對這棵滿二叉樹進行先序遍歷,窮竭遍歷所有的狀態,當匹配到

sum == k時,那麼從這個節點開始返回根節點,由於要順序輸出組成k的這若干個數,因此我們可以用棧存儲這些數,在我們在匹配

到sum == k時,由於我們要沿著根節點的路徑返回,直至返回整棵樹的根節點,因此我們可以在返回的路徑中,將途經的數據元

素壓入棧中。直至返回到整棵樹的根節點時,將棧中元素一一輸出即可。

當然,這道題也可以進行一些剪枝操作,比如說此時遍歷到的節點sum值已經大於k時,那麼該節點的孩子節點則不必再遍

歷。<喎?/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPjxzdHJvbmc+0vK0y7/J0tSyu7HYw7+0zra8senA+rW90ra92rXj1Nm72Mvdo6zV4tH5tcS7sMqhyKXBy7K7sdjSqrXEsenA+rLZ1/ehozwvc3Ryb25nPjwvcD4KPHA+zerV+7T6wuvKtc/Wo7o8L3A+CjxwPjwvcD4KPHByZSBjbGFzcz0="brush:java;">#include #include #include using namespace std; const int MAX_N = 25; int n,k,flag,num[MAX_N]; stack s; //i表示當前考慮到了哪個數,sum表示當前和 bool dfs(int i,int sum){ if(sum > k){ return false; //剪枝操作 } //如果前n項均已經計算過,那麼判斷此時sum的值是否與k相等,並回溯至上一層 if(i==n){ return k==sum; } //加上a[i]的情況 if(dfs(i+1,sum+num[i])){ s.push(num[i]); return true; } //不加上a[i]的情況 if(dfs(i+1,sum)){ return true; } return false; } int main(){ //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); while(scanf("%d %d",&n,&k)!=EOF){ memset(num,0,sizeof(num)); for(int i = 0;i < n;++i){ scanf("%d",&num[i]); } if(dfs(0,0)){ printf("YES\n"); while(!s.empty()){ printf("%d ",s.top()); s.pop(); } printf("\n"); } else{ printf("NO\n"); } } return 0; }

C題:

C題題目鏈接

題目描述:

T^T又有數學問題了

TimeLimit:1000MSMemoryLimit:65536KB 64-bit integer IO format:%I64d
Problem Description

T^T 是個很厲害的選手,除了喜歡寫17kb+的代碼題,偶爾還會寫數學題.他找到了一個數列:

1461106845517018941.jpg


他給了你幾個數:n,a,b,c,你需要告訴他fn模p後的數值.

Input

第一行一個數T,為測試數據組數.

每組數據一行,一行五個正整數,按順序為n,a,b,c,p.


1≤T≤10,1≤n≤10^18,1≤a,b,c≤10^9,p是質數且p≤10^9+7

Output

對每組數據輸出一行一個數,輸出fn對p取模後的數值.


SampleInput
1
5 3 3 3 233
SampleOutput
190
解析:

這道題沒有完整代碼提供,因為這道題還有沒有弄明白的地方,而且雛形代碼一直沒調試好:-(,這裡提供簡要思路

對於這樣的題目,一開始拿到手的時候沒有什麼明朗的思路,因此我們可以試著枚舉前幾項,看看是否從特殊的角度發現其一般規

律。

f1 = 1;

f2 = a^b;

f3 = a^b * a^(bc) * 1 = a^[b(1+c)];

f4 = a^b * f3^c * f2 = a^[b(c^2 + c + 2)];

f5 = a^b * f4^c * f3 = a^[b(c^3 + c^2 + 3*c + 2)];

f6 = a^b * f5^c * f4 = a^[b(c^4 + c^3 + 4 * c ^ 2 + 3*c + 3)];

枚舉到第六項,我們發現,每一項都有其相同的部分,因此我們可以去掉相同的部分,看剩余不同的部分是否有規律:

0 ---------> f1

1 ---------> f2

1+c ---------> f3

c^2 + c + 2 ---------> f4

c^3 + c^2 + 3*c + 2 ---------> f5

c^4 + c^3 + 4 * c ^ 2 + 3*c + 3 ---------> f6

仔細觀察,其實不難發現,每一項(第三項及第三項之後)都與其前兩項是有聯系的。比如說f3,f4,f5.我們可以找到它們之間的這樣

的關系:

f3 + f4 * c + 1 = f5;

而有了這樣的推論之後,我們可以發現:f(n) = c * f(n-1) + f(n-2) + 1;

而多項式之間的關系,則可以借助於矩陣來解決,對於有常數項的多項式,則用三維矩陣即可(常數視為第三維)。

因此有了以上的推論,我們可以構造出這樣的初始矩陣以及冪矩陣:

\

因此我們則可以將初始矩陣記為A矩陣,冪矩陣記為B矩陣,這樣的話,要求fn,則即求A * B ^ (n-1),然後取結果矩陣的首項即可。

而要求A * B ^ (n-1),則可用矩陣快速冪求解。

但是,這道題還有兩個要注意的小細節:

1.B ^ (n-1)指數過大,long long已經無法存儲,我個人有個想法:

(1).對等式兩邊運用log函數,以a為底,這樣的話,就把冪指數降下來了。

(2).第二個辦法是從福州大學陳鴻數論pdf文檔中看到了一個結論:

\

這個結論我暫時沒有辦法解釋,涉及到歐拉函數和費馬小定理,證明過程在這裡,有興趣的可以一起研究探討:

求解x=a^b(mod m)

2.注意特判a與p不互質(a mod p = 0)的情況。

E題:

E題題目鏈接

題目描述:

Complicated GCD

TimeLimit:1000MSMemoryLimit:256MB 64-bit integer IO format:%I64d
Problem Description

Greatest common divisorGCD(a,?b)of two positive integersaandbis equal to the biggest integerdsuch that both integersaandbare divisible byd. There are many efficient algorithms to find greatest common divisorGCD(a,?b), for example, Euclid algorithm.

Formally, find the biggest integerd, such that all integersa,?a?+?1,?a?+?2,?...,?bare divisible byd. To make the problem even more complicated we allowaandbto be up to googol,10100— such number do not fit even in 64-bit integer type!

Input

The only line of the input contains two integersaandb(1?≤?a?≤?b?≤?10100).

Output

Output one integer— greatest common divisor of all integers fromatobinclusive.

SampleInput 1
1 2
SampleOutput 1
1
SampleInput 2
61803398874989484820458683436563811772030917980576 61803398874989484820458683436563811772030917980576
SampleOutput 2
61803398874989484820458683436563811772030917980576
題意:

給定a,b,找出能夠整除閉區間[a,b]中所有的數的最大整數。

解析:

簡單題,考慮當a == b時,顯然這個數就是其本身,而當a != b時,由於連續的兩個正整數的公共因子只有1(可用反證法證明),因此

答案則是1.

完整代碼實現:

#include
#include
using namespace std;
int main(){
    string a,b;
    cin >> a >> b;
    if(a==b){
        cout << a << endl;
    }
    else{
        cout << 1 << endl;
    }
    return 0;
}

F題:

F題題目鏈接

題目描述:

Solve equation

TimeLimit: 1000msMemoryLimit:32768KB 64-bit integer IO format:%I64d
Problem Description

You are given two positive integers A and B in Base C. For the equation:

A=k*B+d

We know there always existing many non-negative pairs (k, d) that satisfy the equation above. Now in this problem, we want to maximize k.

For example, A="123" and B="100", C=10. So both A and B are in Base 10. Then we have:

(1) A=0*B+123

(2) A=1*B+23

As we want to maximize k, we finally get one solution: (1, 23)

The range of C is between 2 and 16, and we use 'a', 'b', 'c', 'd', 'e', 'f' to represent 10, 11, 12, 13, 14, 15, respectively.

Input

The first line of the input contains an integer T (T≤10), indicating the number of test cases.

Then T cases, for any case, only 3 positive integers A, B and C (2≤C≤16) in a single line. You can assume that in Base 10, both A and B is less than 2^31.

Output For each test case, output the solution “(k,d)” to the equation in Base 10. SampleInput
3
2bc 33f 16
123 100 10
1 1 2
SampleOutput
(0,700)
(1,23)
(1,0)
題意:

給定一個數T,表示有T組測試數據,然後每行有三個數,分別是A,B,C。C表示給定的A,B數的進制,然後題目要求你將A,B轉換成十

進制後,找出一個最大的數k,使得k,d滿足A = k * B + d(其中k,d均為非負整數)。

解析:

顯然我們要將其轉換成十進制數之後,然後按照格式輸出即可。注意這道題不要去用pow()函數從後往前計算A,B兩數十進制所表示

的數,會判CE或者WA,原因未知。無論如何,涉及到浮點數的函數,還是要慎用,能不用則不用。

因此我們從前往後考慮即可,每往後計算一位,則標記數乘以相應進制即可。

完整代碼實現:

#include
#include
#include
using namespace std;
typedef long long ll;
void solve(){
    int T,radix,tmp;
    char str1[50],str2[50];
    scanf("%d",&T);
    while(T--){
        scanf("%s %s %d",str1,str2,&radix);
        int a = 0,b = 0;
        for(int i = 0;str1[i] != '\0';++i){
            a *= radix;
            if(str1[i] >= 'a'){
                a += str1[i] - 'a' + 10;
            }
            else{
                a += str1[i] - '0';
            }
        }
        for(int i = 0;str2[i] != '\0';++i){
            b *= radix;
            if(str2[i] >= 'a'){
                b += str2[i] - 'a' + 10;
            }
            else{
                b += str2[i] - '0';
            }
        }
        //printf("%d %d",a,b);
        printf("(%d,%d)\n",a/b,a%b);
    }
}
int main(){
    solve();
    return 0;
}

總結:不要過度依賴庫函數,編碼能力還是不強,要多鍛煉,而且以後題目盡量要自己慢慢弄懂,這樣才會是自己的東西。


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved