1. 程式人生 > 實用技巧 >8.13訓練

8.13訓練

https://ac.nowcoder.com/acm/contest/7055

B-Icebound and Squence

思路:本來以為是用等比數列求和公式做的,結果做不出來,隊友用的遞迴吧算是,和一個奇怪的公式

AC程式碼:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
ll quick(ll q,ll n,ll p){
    ll ans=1,base=q;
    while(n){
        if
(n&1) ans=ans*base%p; base=base*base%p; n>>=1; } return ans; } ll solve(ll q,ll n,ll p){ if(n==1) return q%p; else if(n%2==0) return (solve(q,n/2,p)+quick(q,n/2,p)*solve(q,n/2,p))%p; else return (solve(q,n/2,p)+quick(q,n/2,p)*solve(q,n/2,p)+quick(q,n,p))%p; } int
main(){ int t; cin>>t; while(t--){ ll q,n,p; cin>>q>>n>>p; cout<<solve(q,n,p)%p<<endl; } return 0; }

C-分治

題面是漢語,也不難理解,就不說了。

思路:這道題看到感覺可以小區間推大區間,就用的區間dp.

狀態轉移方程:

if(k==j) dp[j][i+j-1]=min(dp[j][i+j-1],a[k]*(i-1)+dp[j+1
][i+j-1]); else if(k==j+i-1) dp[j][i+j-1]=min(dp[j][i+j-1],a[k]*(i-1)+dp[j][i+j-2]); else dp[j][i+j-1]=min(dp[j][i+j-1],dp[j][k-1]+dp[k+1][i+j-1]+(i-1)*a[k]);//怕錯,分的比較細

其實就是j到i+j-1這個區間的時候,你需要暴力列舉假設從k處分開,而且小於距離i最優子空間都是已知的,於是描述一下就可以。

感受:思路其實已經有了,但是中間因為看錯題,改了老半天,不過只已經可以訓練中做出來這種dp題了(因為不會分治)

最後就是它和之前的石子合併很像

AC程式碼:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
ll a[3100],dp[2100][2100];
int main(){
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        memset(dp,0x3f3f3f3f,sizeof(dp));
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        for(int i=1;i<=n;i++) dp[i][i]=0;
        for(int i=2;i<=n;i++){
            for(int j=1;j<=n-i+1;j++){
                for(int k=j;k<=j+i-1;k++){
                    if(k==j) dp[j][i+j-1]=min(dp[j][i+j-1],a[k]*(i-1)+dp[j+1][i+j-1]);
                    else if(k==j+i-1) dp[j][i+j-1]=min(dp[j][i+j-1],a[k]*(i-1)+dp[j][i+j-2]);
                    else dp[j][i+j-1]=min(dp[j][i+j-1],dp[j][k-1]+dp[k+1][i+j-1]+(i-1)*a[k]);
                }
            }
        }
        cout<<dp[1][n]<<endl;
    }
}

L-smart robot

思路:一道搜尋的題目,不過你得知道搜到幾位數就行,xx學長給了個式子:10^k<n*n*4^k(k表示深度)然後直接搜就行。

AC程式碼:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int M=1e6+2;
int s[2100][2100],vis[2200000],n;
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
void dfs(int x,int y,int num,int step){
    if(step>=6) return ;
    vis[num]=1;
    for(int i=0;i<4;i++){
        int fx=x+dx[i];
        int fy=y+dy[i];
        if(fx<=n&&fx>=1&&fy>=1&&fy<=n){
            dfs(fx,fy,num*10+s[fx][fy],step+1);
        } 
    }
    return ;
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cin>>s[i][j];
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            dfs(i,j,s[i][j],0);
        }
    }
    for(int i=0;i<=M;i++){
        if(!vis[i]){
            cout<<i<<endl;
            break;
        }
    }
    return 0;
}

J-舔狗

思路:由於邊數只有一個環,從入度較少的點慢慢往前更新刪除,就算拆了環也沒有關係。

感受:自己程式碼能力不強,只能去靠隊友,欸,補的題。

AC程式碼:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring> 
using namespace std;
const int M=1e6+5;
int x,n,a[M],vis[M],in[M];
struct node{
    int u,v;//u為編號,v為入度
    bool friend operator<(node x,node y){
        return x.v>y.v;
    } 
};
void solve(){
    int ans=0;
    priority_queue<node>q;
    for(int i=1;i<=n;i++){
        q.push(node{i,in[i]});
    }
    while(!q.empty()){
        node cur=q.top();q.pop();
        if(vis[a[cur.u]]||vis[cur.u]) continue;
        ans+=2;
        vis[cur.u]=1;
        vis[a[cur.u]]=1;
        q.push(node{a[a[cur.u]],--in[a[a[cur.u]]]});
    }
    cout<<n-ans<<endl;
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        in[a[i]]++;
    }
    solve();
    return 0;
}