1. 程式人生 > >第四屆“圖靈杯”NEUQ-ACM 程式設計競賽(團隊賽)

第四屆“圖靈杯”NEUQ-ACM 程式設計競賽(團隊賽)

題目描述
NEUQ的穀神要和我賭一個遊戲:穀神要求我隨機在紙上寫出整數集合{1,2,3,…,3n+1}(n是整數)的一個排列(即不重複的隨機寫出從1到3n+1的所有整數)。並且要求在我寫的過程中,從我寫的第一個數開始一直加到我正在寫的數的總和不被3整除。如果我能寫出來符合要求的一個排列,那麼我就贏得遊戲。那麼問題來了,我贏得遊戲的概率是多少?

輸入
一組測試資料,第一行輸入測試樣例的數目k,接下來k行每行一個正整數n代表一個樣例(1<=n<=15)。

輸出
對於每個樣例資料依次輸出我贏得比賽的概率(結果保留小數點後9位有效數字)。

樣例輸入
1
1
樣例輸出
0.250000000
提示


例如n=1,則穀神要求我隨機寫1到4的排列,如果我按順序寫1 3 4 2則是合法的,因為1,1+3、1+3+4、1+3+4+2都不被3整除。如果我按順序寫1 2 3 4則是不合法的,因為當我寫到2的時候1+2=3可以被3整除,不符合遊戲規定。

這道題剛上來思路是對的,式子推半天沒推出來,後來發現是0的位置的問題
因為要問加起來的這個數能不能被3整除,所以我們可以直接把所有數想成0,1,2,0一共有i個,1一共有i+1個,2一共有i個,所以問題放在瞭如何排列這道題上
我們先排1:一共有i!種
然後排2:因為最後的0不會影響最後的加法,所以你可以試一試2可以放在那些位置,最後發現只能擺成 1 1 2 1 2 1 2這種的形式,所以2一共有(i+1)!種
最後排0:剛開始0可以放到(2i+1)個地方(第一個位置不可以放!),然後第二個0可以放到(2i+2)個地方,一共有i個,所以一共可以放到3i個地方
所以最後的式子就變成了i!*(i+1)!*(2i+1)*(2i+2)…*3i/(3i+1)!


附上AC程式碼:

#include<bits/stdc++.h>
using namespace std;
using LL=int64_t;
const int INF=0x3f3f3f3f;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T;
    cin>>T;
    for(int i=0;i<T;i++) {
        int temp;
        double sum=1;
        cin>>temp;
        for(int
i=1;i<=temp;i++) sum*=(double)i; for(int i=temp+2;i<=temp*2;i++) sum/=(double)i; sum/=(double)(3*temp+1); cout<<fixed << setprecision(9) << sum<<endl; } return 0; }

題目描述
實驗班最近在準備購置新的書籍。現在統計出了一份有十本書的書單,但是由於預算有限,必須刪掉一本書。大家討論決定把價格第三高的書刪掉,請你找出這本書。

輸入
第一行是一個整數T(1<=T<=1000),表示有T組資料。接下來的T行,每行有十一個整數,第一個整數表示這是第幾組輸入資料,接下來的十個整數表示你要處理的十本書的價格。每組資料用空格分隔,書的價格不超過1000。

輸出
對每組輸入資料,輸出它的組號和第三高的價格,用空格分隔。

樣例輸入
3
1 1 2 3 4 5 6 7 8 9 10
2 931 240 986 894 826 640 965 833 136 138
3 940 955 364 188 133 254 501 122 768 408
樣例輸出
1 8
2 931
3 768

AC程式碼:

#include<bits/stdc++.h>
using namespace std;
using LL=int64_t;
const int INF=0x3f3f3f3f;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n,x;
    cin>>n;
    for(int i=1;i<=n;i++) {
        int ans[10];
        cin>>x;
        for(int j=0;j<10;j++)
            cin>>ans[j];
        sort(ans,ans+10);
        cout<<i<<" "<<ans[7]<<endl;
    }
    return 0;
}

題目描述
這是一個斐波那契數列:
f1 = 1
f2 = 2
fn = fn-1 + fn-2 (n>=3)
蔡老闆想知道,給你兩個數a、b,你能否求出在區間[a,b]裡有多少個斐波那契數。

輸入
多組資料輸入。一行為一組輸入資料,包括兩個非負整數a、b(a <= b <= 10^100),當a=b=0時輸入終止。

輸出
對每組輸入,輸出單獨一行,包含一個整數表示區間[a,b]裡的斐波那契數個數。

樣例輸入
10 100
1234567890 9876543210
0 0
樣例輸出
5
4

這道題除錯了好久,最後終於調出來了,就是判斷a,b的時候a和b有一個可能為0,我想的方法是先把前1000個斐波那契寫出來然後判斷,寫斐波那契確實費了一些時間,還有關於範圍的確定也確實好費事
附上AC程式碼:

#include<bits/stdc++.h>
using namespace std;
using LL=int64_t;
const int INF=0x3f3f3f3f;
const int num=1005;

int fib[num][105];
int temp[num][105];
int length[num];
void init()
{
    memset(temp,0,sizeof(temp));
    memset(fib,0,sizeof(fib));
    temp[0][0]=fib[0][0]=1,temp[1][0]=fib[1][0]=1;
    length[0]=0;length[1]=0,length[2]=0;
    for(int i=2;i<num;i++) {
        for(int j=0;j<105;j++) {
            temp[i][j]+=temp[i-1][j]+temp[i-2][j];
            if(temp[i][j]>=10) {
                temp[i][j]-=10;
                temp[i][j+1]++;
            }
        }
        for(int j=104;j>=0;j--)
            if(temp[i][j]>0) {
                length[i]=j;
                break;
            }
        for(int j=length[i];j>=0;j--)
            fib[i][length[i]-j]=temp[i][j];
    }
}

bool compear1(string x,int n) {
    if(x.length()<length[n]+1) return true;
    if(x.length()>length[n]+1) return false;
    for(int i=0;i<x.length();i++) {
        if(fib[n][i]>x[i]-'0') return true;
        if(fib[n][i]<x[i]-'0') return false;
    }
    return true;
}

bool compear2(string x,int n) {
    if(x.length()>length[n]+1) return true;
    if(x.length()<length[n]+1) return false;
    for(int i=0;i<x.length();i++) {
        if(fib[n][i]<x[i]-'0') return true;
        if(fib[n][i]>x[i]-'0') return false;
    }
    return true;
}

int main()
{
    init();
    ios::sync_with_stdio(0);
    cin.tie(0);
    string a,b;
    while(cin>>a>>b) {
        if(a=="0"&&b=="0") break;
        int temp1=0,temp2=0;
        for(int i=1;i<num;i++) {
            if(compear1(a,i)) {
                temp1=i;break;
            }
        }
        for(int i=num-1;i>=1;i--) {
            if(compear2(b,i)) {
                temp2=i;break;
            }
        }
        cout<<temp2-temp1+1<<endl;
    }
    return 0;
}

下面是標程:

/*
先算前480個fibs,然後二分確定a和b數列fibs裡的位置,ab兩位置求個差值,就可以得到他們中間包含的fibs個數。
a和b也是fibs的情況特判一下。
*/

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

#define MAXN    500
#define MAXLEN  110
#define LAST MAXLEN-2

char store[MAXN][MAXLEN];
char *Fibs[MAXN];

char* IntAddition(char *a,char *b,char *sum){
    int i,j,k,first;
    for(i=strlen(a)-1,j=LAST;i>=0;i--,j--){
        sum[j]=a[i]-'0';
        }
    for(i=strlen(b)-1,k=LAST;i>=0;i--,k--){
        sum[k]+=b[i]-'0';
        }
    first=j<k?j:k;
    for(i=LAST;i>=first;i--){
        sum[i-1]+=sum[i]/10;
        sum[i]=sum[i]%10+'0';
        }
    while(sum[first]=='0'&&first<LAST){
        first++;
        }
    return &sum[first];
    }

void Fibonacci(void){
    memset(store,0,sizeof(store));
    memset(Fibs,NULL,sizeof(Fibs));

    strcpy(store[1],"1");
    strcpy(store[2],"2");
    Fibs[1]=store[1];
    Fibs[2]=store[2];

    int i;
    for(i=3;i<485;i++){
        Fibs[i]=IntAddition(Fibs[i-2],Fibs[i-1],store[i]);
        }
    }

int Compare(char *a,char *b){
    int lenA=strlen(a);
    int lenB=strlen(b);
    if(lenA==lenB)
        return strcmp(a,b);
    return lenA>lenB?1:-1;
    }

int BinarySearch(char *num,bool &flag){
    int low=1;
    int high=480;   
    while(low<=high){
        int mid=(low+high)/2;
        int res=Compare(num,Fibs[mid]);
        if(res==0){
            flag=true;
            return mid;
            }
        else if(res<0)
            high=mid-1;
        else
            low=mid+1;
        }
    return low;
    }

int main(){
    Fibonacci();
    char a[MAXLEN],b[MAXLEN];
    while(scanf("%s %s",a,b)!=EOF){
        if(strcmp(a,"0")==0&&strcmp(b,"0")==0){
            break;
            }
        bool flagLeft=false;
        bool flagRight=false;
        int left=BinarySearch(a,flagLeft);
        int right=BinarySearch(b,flagRight);
        if (flagRight)
            printf("%d\n",right-left+1);
        else
            printf("%d\n",right-left);
        }
    return 0;
    }

題目描述
謝爾賓斯基三角形是一種分形,它的構造過程是這樣的:
1.取一個實心的三角形。(多數使用等邊三角形)
2.沿三邊中點的連線,將它分成四個小三角形。
3.去掉中間的那一個小三角形。
4.對其餘三個小三角形重複1。
我們想嘗試用斜線、反斜線和下劃線畫出謝爾賓斯基三角,假設最小的三角是長這樣的:
/\
/__\
具體規律詳見樣例。
輸入
多組資料輸入輸出。每行有一個整數n(1<=n<=10),表示執行了一次操作1,n=0時結束輸入。

輸出
畫出執行n次操作1後的圖形,調整你的輸出到最左端(底邊的第一個斜槓在第一列)。輸出不能包含任何尾隨空格。在每個測試用例後列印空行。

樣例輸入
3
2
1
0
樣例輸出
/\
/__\
/\ /\
/\/\
/\ /\
/\ /\
/\ /\ /\ /\
/\/\/\/\

/\
/__\
/\ /\
/\/\

/\
/__\

遞迴題,標程程式碼:

//遞迴
#include <cstdio>
#include <cstring>
#define N 2050
using namespace std;
int n;
char s[N/2][N];

void print(int x,int y,int d){
    int offset=1<<(d-1);
    if(d==1){
        s[x][y]=s[x+1][y-1]='/';
        s[x][y+1]=s[x+1][y+2]='\\';
        s[x+1][y]=s[x+1][y+1]='_';
        return ;
        }
    print(x,y,d-1);
    print(x+offset, y-offset, d-1);
    print(x+offset, y+offset, d-1);
    }

int main(){
    while(scanf("%d",&n) && n){
        int i,j,k;
        for(i=1;i<=(1<<n);i++)
            for(j=1;j<=(1<<(n+1));j++)
                s[i][j]=' ';
        print(1,(1<<n),n);
        k=(1<<n)+1;
        for(i=1;i<=(1<<n);i++,k++){
            for(j=1;j<=k;j++)
                putchar(s[i][j]);
            printf("\n");
            }
        printf("\n");
        }
    return 0;
    }

題目描述
那麼大奶牛之神把一個神祕數字通過信使傳遞給了奶牛們,但由於信件上出現了偏差,一個數字變成了兩個數字,現在你需要通過這兩個數字還原出大麼大奶牛之神給的神祕數字。需要用第二個數字通過加(+),減(-),乘(*),除(/),次冪(^),階乘(!),開平方(√)這幾個符號湊出第一個數字。使用第二個數字的次數最少的時候,那麼使用次數就是神祕數字。

例如第一個數字是300,第二個數字是7,那麼7用得最少是6次,所以神祕數字是6。具體方法如圖用了6個7。雖然最優解的算式不是唯一的,但是並不妨礙得到最少的使用次數。
這裡寫圖片描述

現在得知第一個數字是51,第二個數字是整數n(0< n< 10),求神祕數字。

輸入
輸入n(0< n<10)

輸出
輸出神祕數字

樣例輸入
1
樣例輸出
8
傳說中的真正防AK題,出奇的腦洞,官方題解是找規律…..

51#1最優解1+(111-11)/(1+1)
51#2最優解2+2/2+2*(2*2)!
51#3最優解3!*3+33
51#4最優解4!*(√4+√√√(√4^(-4!)))
51#5最優解5/5+55-5
51#6最優解(6!-6*6)/(6+6)-6
51#7最優解7*7+(7+7)/7
51#8最優解√√(8+8)+√(√(8-8/8)^8)
51#9最優解(√9)!*9-√9
51的9個最優解是864456563

標程:

#include<iostream>
using namespace std;
int main()
{
    int n,a[10]={0,8,6,4,4,5,6,5,6,3};
    while (cin >> n){
        cout << a[n] << endl;
    }
    return 0;
}

題目描述
這是一道拼手速的題!

你在跟acmclub機器人對話。對它說:“Is this NEUQ?”,它會回答你:“Yes, welcome to NEUQ.”。對它說:“I have some question!”,它會回覆:“What can I do for you?”。

輸入
輸入為一句話。

輸出
輸出也為一句話。

樣例輸入
Is this NEUQ?
樣例輸出
Yes, welcome to NEUQ.

注意第一句Is this NEUQ?的問號是中文問號
AC程式碼:

#include<bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    string q;
    getline(cin,q);
    if(q=="Is this NEUQ£¿") cout<<"Yes, welcome to NEUQ."<<endl;
    if(q=="I have some question!") cout<<"What can I do for you?"<<endl;
    return 0;
}

題目描述
變位詞是指改變某個詞的字母順序後構成的新詞。蔡老闆最近沉迷研究變位詞並給你扔了一道題:

給你一些單詞,讓你把裡面的變位詞分組找出來。互為變位詞的歸為一組,最後輸出含有變位詞最多的前五組。如果有組數相同的按照字典序輸出。

輸入
輸入包含由小寫字母組成的單詞,用換行分割,被EOF終止。 輸入資料不超過30000個單詞。

輸出
輸出五組包含單詞數量最多的變位詞,如果少於五組,輸出全部。對每組輸出,寫出它的大小和成員詞,成員詞按字典序排序用空格分隔,每組輸出之間用換行分隔,相同詞只輸出一次,但算個數。

樣例輸入
neuq
tea
bate
beat
caret
trace
nueq
carte
cater
crate
abet
ate
eat
beta
eta
signal
樣例輸出
Group of size 5: caret carte cater crate trace .
Group of size 4: abet bate beat beta .
Group of size 4: ate eat eta tea .
Group of size 2: neuq nueq .
Group of size 1: signal .

這道題寫了一中午+半下午,其實最主要的就是要靈活運用STL中的各種容器,這道題我的思路就是首先一個map< key,value>第一個key是按字典序排好的,第二個是一個set用來儲存字典序相同的string,然後再用一個map< key,value>用來儲存按字典序排好的string對應的數量,然後找到數量最多的,如果數量相同,就在比較字典序最後輸出

附上AC程式碼:

#include<bits/stdc++.h>
using namespace std;
map<string,set<string> >ans;
map<string,int>cnt;
map<string,int>::iterator is;
set<string>::iterator its;
int main()
{
    string x;
    while(cin>>x) {
        string temps=x;
        sort(x.begin(),x.end());
        ans[x].insert(temps);
        cnt[x]++;
    }
       string max_temp;
        int time=0;
        while(time<5&&ans.size()) {
        int maxn=0;
        for(is=cnt.begin();is!=cnt.end();is++) {
            if(is->second > maxn) {maxn=is->second;max_temp=is->first;}
            else if(is->second==maxn) {
            if(*ans[is->first].begin()<*ans[max_temp].begin())
                    max_temp=is->first;
            }
          }
        cout<<"Group of size "<<maxn<<": ";
        for(its=ans[max_temp].begin();its!=ans[max_temp].end();its++) {
            cout<<*its<<" ";
        }
        cout<<"."<<endl;
        time++;
        ans.erase(max_temp);
        cnt.erase(max_temp);
      }
    return 0;
}

下面附上標程:

/*
所有字串統計字元後hash,排完序就確定每組的個數、確定一組中字典序最小的字串。
再根據個數以和字串對組進行排序。
*/

#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;

const int maxn=30005;
const int maxm=30;
const int X=30;
typedef unsigned long long ll;
typedef pair<ll,int> pii;

int N,M,E;
vector<pii> vec,grop;
vector<int> g[maxn];
char word[maxn][maxm],st[maxn][maxm];

inline ll Hash(char* s){
    int len=strlen(s),c[maxm];
    memset(c,0,sizeof(c));
    for(int i=0;i<len;i++)
        c[s[i]-'a']++;
    ll ret=0;
    for(int i=0;i<26;i++)
        ret=ret*X+c[i];
    return ret;
    }

inline bool cmp (const pii& a,const pii& b){
    if(a.second==b.second)
        return strcmp(st[a.first],st[b.first])<0;
    return a.second>b.second;
    }

inline bool sort_by(const int& a,const int& b){
    return strcmp(word[a],word[b])<0;
    }

int main(){
    N=M=E=0;
    vec.clear();
    grop.clear();
    while(scanf("%s",word[N])==1){
        ll key=Hash(word[N]);
        vec.push_back(make_pair(key,N));
        N++;
        }
    sort(vec.begin(),vec.end());
    int cnt=0;
    ll pre=-1;
    for(int i=0;i<vec.size();i++){
        int idx=vec[i].second;
        if(vec[i].first!=pre){
            if(cnt)
                grop.push_back(make_pair(M++,cnt));
            cnt=0;
            g[M].clear();
            pre=vec[i].first;
            strcpy(st[M],word[idx]);
            }
        cnt++;
        g[M].push_back(idx);
        if (strcmp(word[idx],st[M])<0)
            strcpy(st[M],word[idx]);
        }
    if (cnt)
        grop.push_back(make_pair(M++,cnt));
    sort(grop.begin(),grop.end(),cmp);

    for(int i=0;i<min(5,(int)grop.size());i++){
        printf("Group of size %d: ",grop[i].second);
        int x=grop[i].first;
        sort(g[x].begin(),g[x].end(),sort_by);
        for (int j=0;j<g[x].size();j++){
            if (j==0||strcmp(word[g[x][j-1]],word[g[x][j]]))
                printf("%s ",word[g[x][j]]);
            }
        printf(".\n");
        }
    return 0;
    }