1. 程式人生 > >第15屆上海大學程式設計聯賽夏季賽

第15屆上海大學程式設計聯賽夏季賽

A:黑白影象直方圖

描述
在一個矩形的灰度影象上,每個畫素點或者是黑色的或者是白色的。黑色畫素點用1表示,白色畫素點用0表示。現在要求你編寫一個程式,計算每列上黑色畫素點的個數並輸出。如下圖所示是一個6∗8的黑板影象。

1 1 0 0 1 1 1 1
0 1 1 0 1 0 1 0
1 1 1 1 0 1 1 0
0 1 1 0 0 1 0 0
1 0 1 0 0 1 0 0
0 1 0 1 0 1 1 0

輸入
輸入有多組組。
每組的第一行有2個整數m、n,(1<=m,n<=100)。
接著有m行,每行有n個數字,每個數字是0或1,之間用一個空格分開。

輸出
對影象資料,依次一行輸出影象中每列黑色畫素點的總數。

樣例輸入1
3 5
1 1 0 0 1
0 1 1 0 1
1 1 1 1 0
6 8
1 1 0 0 1 1 1 1
0 1 1 0 1 0 1 0
1 1 1 1 0 1 1 0
0 1 1 0 0 1 0 0
1 0 1 0 0 1 0 0
0 1 0 1 0 1 1 0
樣例輸出1
2 3 2 1 2
3 5 4 2 2 5 4 1

#include<bits/stdc++.h>
using namespace std;
using LL=int64_t;
const int INF=0x3f3f3f3f;
int ans[101][101];
int main()
{
    ios::sync_with_stdio(0
); cin.tie(0); int n,m; while(cin>>n>>m) { memset(ans,0,sizeof(ans)); for(int i=0;i<n;i++) { for(int j=0;j<m;j++) cin>>ans[i][j]; } for(int i=0;i<m;i++) { int count=0; for(int j=0;j<n;j++) { if
(ans[j][i]==1) count++; } if(i==0) cout<<count; else cout<<" "<<count; } cout<<endl; } return 0; }

B:神無月排位賽

描述
《神無月》作為盛大遊戲2017年的全新原創大作,其開發團隊在自研實力強大的傳世工作室基礎之上,還有美樹本晴彥等日本一線知名畫師及日本遊戲音樂大師崎元仁加盟參與制作。目前正在不限號內測中,有很多玩家進入到神無月的世界中。

在神無月中,有著玩家之間切磋的排位賽,其段位主要分為五大段位,從低到高依次為:新兵、菁英、戰將、統帥、王者。每個玩家只有從新兵段位慢慢努力,一點點晉級才能到達王者段位。成為一個王者是每一個玩家的追求和心願。

這裡寫圖片描述

假設神無月的段位系統如下:

從低到高的段位依次簡記為:D、C、B、A、S。玩家打排位賽,每勝利1局增加10分,輸1局扣除5分。每一個段位都需要積分,累計100分才可以進入晉級賽,晉級賽採用三局兩勝制(3局中達到2局勝利就晉級成功,有2局失敗就算晉級失敗, 連勝或連敗兩局,第三局不需要打了)。晉級成功後,成為下一個段位,積分變為0,重新開始算分;如果晉級失敗,則積分變為60,重新開始算分。為方便計算,如果該玩家一直輸,積分降為0後,不再降分,也不會掉段位。

大聖同學最近對神無月非常喜歡,一直在努力成為王者。他從新兵0分開始打排位賽(剛開始處在段位D),他告訴你最近若干場比賽的最後勝利情況,請你寫個演算法猜猜他現在所處的段位。當段位到達S時,段位將不再提高。

輸入
有若干組資料。
每組的第一行為一個N(0

#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;
    while(cin>>n) {
        int rank=0,sum=0;
        for(int i=0;i<n;i++) {
            cin>>x;
            if(x==1) sum+=10;
            else sum-=5;
            if(sum<=0) sum=0;
            if(sum>=100&&i+3<n) {
                int a,b,c;
                cin>>a>>b;
                if(a==0&&b==0) {
                    sum=60;
                    i+=2;
                }
                else if(a==1&&b==1) {
                    rank++;
                    sum=0;
                    i+=2;
                }
                else if(a==1||b==1) {
                    cin>>c;
                    if(c==1) {
                        rank++;
                        sum=0;
                    }
                    else if(c==0) {
                        sum=60;
                    }
                    i+=3;
                }
            }
            else if(sum>=100&&i+2<n) {
                int a,b;
                cin>>a>>b;
                if(a==1&&b==1) {
                    rank++;
                    sum=0;
                    i+=2;
                }
            }
        }
        if(rank==0) cout<<'D'<<endl;
        else if(rank==1) cout<<'C'<<endl;
        else if(rank==2) cout<<'B'<<endl;
        else if(rank==3) cout<<'A'<<endl;
        else if(rank>=4) cout<<'S'<<endl;
    }
    return 0;
}

C :I Love ces

描述
時間過得好快啊,SHU計算機學院又有新的一批小朋友們進來了。2016級的同學想必也是非常喜歡計算機學院的,於是院長想測試一下大家對計算機的喜愛程度(院長大人別查我水錶)。

院長給大家一行由大寫字母(A-Z)和小寫字母(a-z)組成的字串,允許同學們在這個字串裡面任意挑選若干個字元,問最多可以組成多少個I LOVE CES(不區分大小寫,沒有空格,即只要有這8個字元就可以組成一個)。

輸入
多組輸入,每組一行,輸入一個字串。
字串長度<=100000。

輸出
每組輸出一行答案,如題意。

樣例輸入1
IlovecesiLOVECES
樣例輸出1
2

#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);
    string s;
    int ans[20];
    while(cin>>s) {
        memset(ans,0,sizeof(ans));
        for(int i=0;i<s.length();i++) {
            if(s[i]=='i'||s[i]=='I') ans[0]++;
            else if(s[i]=='l'||s[i]=='L') ans[1]++;
            else if(s[i]=='O'||s[i]=='o') ans[2]++;
            else if(s[i]=='v'||s[i]=='V') ans[3]++;
            else if(s[i]=='e'||s[i]=='E') ans[4]++;
            else if(s[i]=='c'||s[i]=='C') ans[5]++;
            else if(s[i]=='s'||s[i]=='S') ans[6]++;
        }
        ans[4]/=2;
        int mins=INF;
        for(int i=0;i<=6;i++)
            mins=min(mins,ans[i]);
        cout<<mins<<endl;
    }
    return 0;
}

D:新增好友

描述
Tony最近喜歡上了龍之谷遊戲,所以他想叫上他的好友組建一個公會來一起享受這款遊戲。

Tony一共有n個好友,他可以叫上任意k(1<=k<=n)個好友來組建公會,並且所有好友都會答應他的請求。問Tony一共可以有多少種方案組建這個公會?

只要不是完全相同的人組建的方案視為不同方案,並且Tony至少要叫上一個人。

輸入
多組輸入,每組一行,輸入一個正整數n(1<=n<=1000000000)。

輸出
每組輸出一行,輸出方案數。(對1000000007取膜)

樣例輸入1
2
樣例輸出1
3

#include<bits/stdc++.h>
using namespace std;
using LL = int64_t;
const int INF = 0x3f3f3f3f;
const int mod=1e9+7;
LL q_pow(LL x,LL n) {
    LL ans=1;
    while(n){
        if(n&1) ans=(ans*x)%mod;
        n>>=1;
        x=(x*x)%mod;
    }
    return ans;
}
int main()
{
    LL n;
    while(cin>>n) {
        cout<<q_pow(2,n)-1<<endl;
    }
    return 0;
}

E:字串進位制轉換

描述
Claire Redfield在龍之谷遊戲的一次任務中獲得了一個上了鎖的寶箱,上面刻了一串由小寫字母構成的字串A和一個數字m。

經過Claire長時間研究,他發現密碼是和a,m有關的。字串A相當於一個26進位制的數字,a相當於0,b相當於1…….z相當於25。然後要將這個26進位制的數轉化成m進位制那就是這個寶箱的密碼。

Claire覺得這個太簡單了所以要你幫她完成。

輸入
多組輸入,每組一行,輸入一個字串A和一個正整數m。
字串長度<=10,2<=m<=9。

輸出
每組輸出一行答案,如題意。

樣例輸入1
b 2
樣例輸出1
1

#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);
    string s;
    int m;
    LL ans[300];
    while(cin>>s>>m) {
        LL sum=0;
        memset(ans,0,sizeof(ans));
        for(int i=0;i<s.length();i++) {
            sum*=26;
            sum+=(LL)(s[i]-'a');
        }
        if(sum==0) cout<<0<<endl;
        else {
        int temp=0;
        while(sum!=0) {
            temp++;
            ans[temp]=sum%m;
            sum/=m;
        }
        for(int i=temp;i>0;i--)
            cout<<ans[i];
        cout<<endl;
        }
    }
    return 0;
}

F:A序列(最長上升子序列)

描述
如果一個序列有奇數個正整陣列成,不妨令此序列為a1,a2,a3,…,a2∗k+1(0<=k),並且a1,a2…ak+1是一個嚴格遞增的序列,ak+1,ak+2,…,a2∗k+1,是一個嚴格遞減的序列,則稱此序列是A序列。

比如1 2 5 4 3就是一個A序列。

現在Jazz有一個長度為n的陣列,他希望讓你求出這個陣列所有滿足A序列定義的子序列裡面最大的那個長度。(子序列可以不連續)

比如1 2 5 4 3 6 7 8 9,最長的A序列子串是1 2 5 4 3。

輸入
多組輸入,每組兩行。
第一行是n,表示給的陣列的長度。
第二行有n個數(int範圍),即給你的陣列。
1<=n<=500000。

輸出
每組輸入輸出一行,即最長的A序列子串的長度。

樣例輸入1
9
1 2 5 4 3 6 7 8 9
樣例輸出1
5

#include<bits/stdc++.h>
using namespace std;
using LL=int64_t;
const int INF=0x3f3f3f3f;
const int maxn=5e4+5;
int ans[maxn],ar[maxn],ax[maxn],l[maxn],r[maxn];
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n;
    while(cin>>n) {
        for(int i=1;i<=n;i++) cin>>ans[i];
        int cnt1=1,cnt2=1;
        l[1]=1,r[n]=1,ar[1]=ans[1];
        for(int i=2;i<=n;i++) {
            if(ans[i]>ar[cnt1]) {
                ar[++cnt1]=ans[i];
                l[i]=cnt1;
            }
            else {
                int pos=lower_bound(ar+1,ar+cnt1,ans[i])-ar;
                ar[pos]=ans[i];
                l[i]=pos;
            }
        }
        ax[1]=ans[n];
        for(int i=n-1;i>0;i--) {
            if(ans[i]>ax[cnt2]) {
              ax[++cnt2]=ans[i];
              r[i]=cnt2;
            }
            else {
                int pos=lower_bound(ax+1,ax+cnt2,ans[i])-ax;
                ax[pos]=ans[i];
                r[i]=pos;
            }
        }
        int sum=0;
        for(int i=1;i<=n;i++)
            sum=max(sum,min(2*l[i]-1,2*r[i]-1));
         cout<<sum<<endl;
    }
    return 0;
}

G:戰鬥

描述
最近,盛大計劃開發一款手遊,以下是簡化版。系統和我方各有n頭怪獸,每一頭怪獸都有生命值和攻擊力,並且當怪獸A攻擊怪獸B,如果怪獸B的生命值高於怪獸A的攻擊力,則怪獸B的生命力減少A的攻擊力的數值,否則怪獸B將死亡。我方已經通過一些手段得知了系統怪獸的出戰序列,我方想要知道,我方是否可以合理安排怪獸的出戰序列,保證當系統的n頭怪獸全部死亡時,而我方至少還存在一頭怪獸。

所有怪獸是每秒攻擊一次,即如果A和B戰鬥,A受到B的傷害的同時,B也受到A的傷害,直到一方死亡,換序列中的下一個怪獸,繼續戰鬥。

輸入
第一行一個整數T,表示測試組數。
對於每組資料,第一行輸入一個整數n,1<=n<=10, 表示怪獸的數目。
接下來n行,表示系統n頭怪獸的出戰序列,每一行兩個整數v,a, 1<=v<=1000, 1<=a<=100. 其中v表示生命值,a表示攻擊力。
接下來n行,表示我方n頭怪獸,但是出戰序列可以由我方自己安排。每行兩個整數,含義類似。

輸出
每組資料輸出一行。如果我方可以通過合理安排怪獸的出戰序列,保證當系統的n頭怪獸全部死亡,而我方至少還存在一頭怪獸,那麼輸出YES;否則輸出NO

樣例輸入1
2
2
5 4
4 3
3 2
5 4
2
5 4
4 3
3 2
5 5
樣例輸出1
NO
YES

寫了兩個版本,第一個沒加優化:

#include<bits/stdc++.h>
using namespace std;
using LL=int64_t;
const int INF=0x3f3f3f3f;
struct Node {
    int blood,cost;
}ans[20],ar[20],a[20],b[20];
int cnt[11]={0,1,2,3,4,5,6,7,8,9};
int n;
bool judge() {
    for(int i=0;i<n;i++) {
        a[i]=ans[i];
        b[i]=ar[cnt[i]];
    }
    int cnt1=0,cnt2=0;
    while(cnt1<n&&cnt2<n) {
        int temp=min(a[cnt1].blood/b[cnt2].cost,b[cnt2].blood/a[cnt1].cost);
        a[cnt1].blood-=b[cnt2].cost*temp;
        b[cnt2].blood-=a[cnt1].cost*temp;
        while(a[cnt1].blood>0&&b[cnt2].blood>0) {
            a[cnt1].blood-=b[cnt2].cost;
            b[cnt2].blood-=a[cnt1].cost;
        }
        if(a[cnt1].blood<=0) cnt1++;
        if(b[cnt2].blood<=0) cnt2++;
    }
    if(cnt1==n&&cnt2<n) return true;
    else return false;
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T;
    cin>>T;
    for(int k=0;k<T;k++) {
        cin>>n;
        for(int i=0;i<n;i++) cin>>ans[i].blood>>ans[i].cost;
        for(int i=0;i<n;i++) cin>>ar[i].blood>>ar[i].cost;
        int flag=0;
        do {
            if(judge()) {
                flag=1;
                break;
            }
        }while(next_permutation(cnt,cnt+n));
        if(flag==1) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

用了1869ms
然後加了下優化:

#include<bits/stdc++.h>
using namespace std;
using LL=int64_t;
const int INF=0x3f3f3f3f;
struct Node {
    int blood,cost;
}ans[20],ar[20],a[20],b[20];
int cnt[11]={0,1,2,3,4,5,6,7,8,9};
int book[11];
int sum[11];
int n;
int nexts=0;
bool judge() {
    for(int i=0;i<n;i++) {
        a[i]=ans[i];
        b[i]=ar[cnt[i]];
    }
    int cnt1=0,cnt2=0;
    while(cnt1<n&&cnt2<n) {
        int temp=min(a[cnt1].blood/b[cnt2].cost,b[cnt2].blood/a[cnt1].cost);
        a[cnt1].blood-=b[cnt2].cost*temp;
        b[cnt2].blood-=a[cnt1].cost*temp;
        while(a[cnt1].blood>0&&b[cnt2].blood>0) {
            a[cnt1].blood-=b[cnt2].cost;
            b[cnt2].blood-=a[cnt1].cost;
        }
        if(a[cnt1].blood<=0) cnt1++;
        if(b[cnt2].blood<=0) cnt2++;
    }
    if(cnt1!=n&&cnt2==n) {
        for(int i=0;i<cnt1;i++)
            book[i]=cnt[i];
        nexts=cnt1;
    }
    if(cnt1==n&&cnt2<n) return true;
    else return false;
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T;
    cin>>T;
    sum[1]=1;
    for(int i=2;i<11;i++) sum[i]=sum[i-1]*i;
    for(int k=0;k<T;k++) {
        cin>>n;
        for(int i=0;i<n;i++) cin>>ans[i].blood>>ans[i].cost;
        for(int i=0;i<n;i++) cin>>ar[i].blood>>ar[i].cost;
        int flag=0;
        do {
            int i;
            if(nexts!=0) {
                for(i=0;i<nexts;i++) {
                    if(book[i]!=cnt[i]) break;
                }
                    if(i==nexts) continue;
                    else {
                        nexts=0;
                        memset(book,0,sizeof(book));
                    }
            }
            if(judge()) {
                flag=1;
                break;
            }

        }while(next_permutation(cnt,cnt+n));
        if(flag==1) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

用了87ms

H:調和序列

描述
給定一個長度為n的非負整數序列,下標為0,1,…,n−1.

定義:sequence(K): 由下標為K的倍陣列成的子序列,即下標為0,K,2K,…,[n−1/k]∗k

query(K,S): 詢問sequence(K)中的第S大的數字

輸入
第一行一個整數T,表示測試組數。
對於每組資料,第一行輸入兩個整數n,m,1<=n<=20000, 1<=m<=100000,n表示序列的長度,m表示詢問個數。
接下來一行是n個整數a0,a1,..,an−1,0<=ai<231, i=0,1,…,n−1,表示序列。
接下來m行,每行兩個整數K,S
0

#include<bits/stdc++.h>
using namespace std;
using LL=int64_t;
const int INF=0x3f3f3f3f;
const int maxn=2e4+5;
int ans[maxn];
int n,m;
vector<int>ar[maxn];

void init() {
    for(int i=1;i<n;i++) {
        ar[i].clear();
        for(int j=0;j<n;j+=i)
        ar[i].push_back(ans[j]);
    }
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T;
    cin>>T;
    for(int k=0;k<T;k++) {
        cin>>n>>m;
        for(int i=0;i<n;i++) cin>>ans[i];
        init();
        int book[maxn];
        memset(book,0,sizeof(book));
        for(int i=0;i<m;i++) {
            int k,s;
            cin>>k>>s;
            if(k>=n) {
                if(s==1) cout<<ans[0]<<endl;
                else cout<<-1<<endl;
            }
            else if(ar[k].size()<s) cout<<-1<<endl;
            else if(book[k]==0) {
                sort(ar[k].begin(),ar[k].end(),greater<int>());
                book[k]=1;
                cout<<ar[k][s-1]<<endl;
            }
            else if(book[k]==1) 
                cout<<ar[k][s-1]<<endl;
        }
    }
    return 0;
}

I:丟史蒂芬妮

描述
有一天,空和白很無聊,決定玩盛大遊戲,考慮到兩個人玩,他們隨便掏了一個遊戲出來:在一個n∗m的棋盤上,首先把史蒂芬妮·多拉放在左上角(1,1)的位置。每次一個人可以將她往下,往右,往右下丟一格。當前回合,誰不能丟史蒂芬妮,誰就輸了。(注意,不可以把活人丟出棋盤啦!)遊戲總是空先手。

白說,這是一個垃圾遊戲!我們每次把史蒂芬妮丟素數個位置吧!(換句話說,每次丟2或3或5或7或…格)空答應了。

我們都知道,空和白都很聰明,不管哪方存在一個可以必勝的最優策略,都會按照最優策略保證勝利。

玩了一局,空已經知道了這個遊戲的套路,現在他決定考考你,對於給定的n和m,空是贏是輸?如果空必勝,輸出“Sora”(無引號);反之,輸出“Shiro”(無引號)。

輸入
第一行有一個T表示陣列組數,1<=T<100000
從第二行開始,每行為棋盤大小,n、m分別表示行列。
1=

#include<bits/stdc++.h>
using namespace std;
using LL=int64_t;
const int INF=0x3f3f3f3f;
const int maxn=1005;
int ans[505][505];

int prime[100]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503};

void init() {
    memset(ans,0,sizeof(ans));
    for(int i=1;i<=500;i++) {
        for(int j=1;j<=500;j++) {
            if(ans[i][j]==0) {
                for(int k=0;;k++) {
                    if(i+prime[k]>500&&j+prime[k]>500) break;
                    if(i+prime[k]<=500) ans[i+prime[k]][j]=1;
                    if(j+prime[k]<=500) ans[i][j+prime[k]]=1;
                    if(i+prime[k]<=500&&j+prime[k]<=500) ans[i+prime[k]][j+prime[k]]=1;
                }
            }
        }
    }
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    init();
    int n,x,y;
    cin>>n;
    for(int i=0;i<n;i++) {
        cin>>x>>y;
        if(ans[x][y]==1) cout<<"Sora"<<endl;
        else cout<<"Shiro"<<endl;
    }
    return 0;
}

K:購買裝備

描述
最近盛大的一款遊戲傳奇世界極其火爆。遊戲玩家John,想購買遊戲中的裝備。已知遊戲的商店裡有n件裝備,第i件裝備具有屬性值ai,購買需要花費bi個金幣。John想去購買這些裝備,但是賬號中只有m個金幣,John是個很貪婪的傢伙,他想購買儘可能多的裝備。並且在保證購買到最多件裝備的情況下,他還想讓他所購買的裝備當中擁有最小屬性值的裝備的屬性值儘可能大。

輸入
輸入測試組數T,每組資料第一行輸入整數n(1<=n<=100000)和m(1<=m<=109), 接下來有n行,第i行有兩個數ai, bi(1<=ai,bi<=10000).

輸出
對於每組資料,輸出兩個數字,第一個數字代表John最多可以購買的裝備數,第二個數代表在John購買最多件裝備的前提下,所購買的裝備當中擁有最小屬性值的裝備的最大屬性值(輸入資料保證至少可以購買一件裝備)

樣例輸入1
1
2 4
3 2
2 3
樣例輸出1
1 3

#include<bits/stdc++.h>
using namespace std;
using LL=int64_t;
const int INF=0x3f3f3f3f;
const int maxn=1e5+5;
struct Node {
    LL a,b;
}ans[maxn];

bool cmp(Node a ,Node b) {
    return a.b<b.b;
}
int sum,n,m;

int check(int num) {
    int count=0,temp=0;
    for(int i=0;i<n;i++) {
        if(ans[i].a>=num) {
            count++;
            temp+=ans[i].b;
        }
        if(temp>m) break;
        if(count==sum) break;
    }
    if(count==sum&&temp<=m) return 1;
    return 0;
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T;
    cin>>T;
    for(int k=0;k<T;k++) {
        LL mins=INF,maxs=0;
        cin>>n>>m;
        for(int i=
        0;i<n;i++) {
            cin>>ans[i].a>>ans[i].b;
            mins=min(mins,ans[i].a);
            maxs=max(maxs,ans[i].a);
        }
        sort(ans,ans+n,cmp);
        int temp=0,count=0;
        sum=0;
        for(int i=0;i<n;i++) {
            if(ans[i].b+temp<=m) {
                sum++;
                temp+=ans[i].b;
            }
            else break;
        }
        while(mins<=maxs) {
            int mid=(mins+maxs)/2;
            if(check(mid)) {
                count=mid;
                mins=mid+1;
            }
            else maxs=mid-1;
        }
        cout<<sum<<" "<<count<<endl;
    }
    return 0;
}