1. 程式人生 > >【高中組集體賽前熱身賽】題解

【高中組集體賽前熱身賽】題解

i++ algo 1.0 iostream 滿足 gin mar print 每一個

(第一次給學弟們學妹寫題解,可能有些地方我認為簡單的可能沒有仔細解釋,所以導致沒有講清楚的一定要勤奮問百度,或者底下留言)

【A-投擲硬幣】

題解:基礎DP(動態規劃),dp[i][j]表示從第一個硬幣開始翻,翻到第i個硬幣的時候,翻到正面的有j個。那麽dp[i][j]由dp[i-1][j-1](第i個是正面)和dp[i-1][j](第i個是反面)轉移而來。所以由方程:dp[i][j]=dp[i-1][j]*(1.0-p[i])+dp[i-1][j-1]*p[i];當然j=0的話只能優dp[i-1][0]轉移而來。

#include<cstdio>
#include<cstdlib>
#include
<cstring> #include<iostream> using namespace std; const int maxn=1010; double dp[maxn][maxn],p[maxn]; int main() { int N,M,i,j; scanf("%d%d",&N,&M); dp[0][0]=1.0; for(i=1;i<=N;i++) scanf("%lf",&p[i]); for(i=1;i<=N;i++){ dp[i][0]=dp[i-1][0
]*(1.0-p[i]); for(j=1;j<=M;j++){ dp[i][j]=dp[i-1][j]*(1.0-p[i])+dp[i-1][j-1]*p[i]; } } printf("%.4lf\n",dp[N][M]); return 0; }

【B-最大集合】

題解:每一個集合是封閉的。即每個元素只會出現在一個集合裏面,而且從每個集合的任意元素出發,都可以走到下一個元素,直到走到起始元素。

所以DFS搜索就可以了,把每次搜索到的標記一下。對於沒有搜索到的,作為起點,繼續搜索。

#include<cstdio>
#include
<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxn=100010; int vis[maxn],a[maxn],cnt; int main() { int N,i,ans=0,tmp; scanf("%d",&N); for(i=1;i<=N;i++) scanf("%d",&a[i]); for(i=1;i<=N;i++){ if(vis[i]==0){ cnt=1; tmp=i; vis[tmp]=1; while(!vis[a[tmp]]){ cnt++; tmp=a[tmp]; } ans=max(ans,cnt); } } printf("%d\n",ans); return 0; }

【C-第K小分數】

枚舉每一個數為分母,然後二分分子。 二分的復雜度是O(logn),然後枚舉N個數作為分母,這樣的話復雜度就是O(N*logN)。不會二分的仔細看代碼就會了。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
const int maxn=1010;
ll a[maxn],N;
ll check(int x,int y)
{
    ll res=0;
    for(int i=1;i<=N;i++){
        res+=(a[i]*x/y);
    } return res;
}
int main()
{
    ll K,L,R,Mid,tmp;
    scanf("%lld%lld",&N,&K);
    for(int i=1;i<=N;i++) scanf("%d",&a[i]);
    for(int i=1;i<=N;i++){
        L=1; R=a[i]-1;
        while(L<=R){
            Mid=(L+R)/2;
            tmp=check(Mid,a[i]);    
            if(tmp==K){
                printf("%lld/%lld\n",Mid,a[i]);
                return 0;
            }
            else if(tmp<K) L=Mid+1;
            else R=Mid-1;
        }
    }return 0;
}

【D-最大子矩陣】

由於A>=1滿足區間和的單調性。所以可以用雙指針,即枚舉矩形的上下邊界,然後移動左右邊界

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=300;
int N,M,K,a[maxn][maxn],sum[maxn][maxn];
int vis[10010],num,Now,ans=-1;
int main()
{
    int i,j,k,L,R;
    scanf("%d%d%d",&N,&M,&K);
    for(i=1;i<=N;i++)
      for(j=1;j<=M;j++){
        scanf("%d",&a[i][j]);
        sum[i][j]=sum[i-1][j]+a[i][j];
    }
    
    for(i=1;i<=N;i++)
      for(j=i;j<=N;j++){ 
         memset(vis,0,sizeof(vis));
         num=0; Now=0;
         for(R=1,L=1;R<=M;R++){
             num+=j-i+1; Now+=sum[j][R]-sum[i-1][R];
             while(Now>K&&L<=R) {
                num-=j-i+1;
                Now-=sum[j][L]-sum[i-1][L];
                L++;
             }
             if(Now<=K&&L<=R) ans=max(ans,num);
         }
    }
    printf("%d\n",ans);
    return 0;
}

【高中組集體賽前熱身賽】題解