1. 程式人生 > 實用技巧 >C# 9.0 中的新增功能

C# 9.0 中的新增功能

太菜了,卡在C上以至於沒有看到D。


A. Marketing Scheme

題意:如果 x mod a ≥⌊a/2⌋,那麼這是好的。問在x∈[l,r]時,能否找到一個a,使得對於區間內任意的x都是好的。

對於區間左端點,a能取得的最大的情況,就是a=2*l了,那麼只要r小於2*l就成立。

B. Reverse Binary Strings

題意:翻轉01串,使之變成01交題串

兩種理解:

1、翻轉一次不會造成內部的變化,只改變首尾兩點。那麼我們找多少個需要被交換的0或者1就行了。

比如(111)那麼就有兩個1需要被翻轉走,需要被交換的01個數取大就好。

        int  cnt1 = 0, cnt2 = 0
; for(int i=1;i<s.length();++i)( { if(s[i]==s[i-1]) { if(s[i]=='1') cnt1++; else cnt2++; } } cout<<max(cnt2,cnt1)<<endl;

2、目標串只有101010以及010101的形式,所以,既然翻轉一次內部方向改變,內部交替不變,那麼我再換一次內部就好了。

比如11101000的目標是10101010,那麼只有2和6號位不匹配,那麼我翻轉2-6,再翻轉3-5就能達成目標。

對於目標是101010,但當中的四位0101都不匹配,那麼我只用翻轉一次就好。

這時候就會有一個問題?當前串01010不匹配呢,翻轉也不行的啊?考慮到其他地方會多一個1不匹配,所以不計也沒關係。

那麼如果一定要多次操作才能還原後面的1呢?那這時候目標串是010101不是更好嗎。

證明不是很嚴謹,當時是看到隊友a了,急中生智,看了一下跟別人的解法都不一樣。

可能是錯的。

memset(vis,0,sizeof(vis));
        ans=anss=0;
        scanf("%d",&n);
        scanf("%s",a+1);
        //10101010
        f=1;
        
for(int i=1;i<=n;++i){ if(a[i]-'0'==f){ } else{ ans++; if(!vis[i]) vis[i]=1;  //需要被交換 if(vis[i-1]) ans--;   //前面一位也被交換,當前位不計貢獻 } f^=1; } memset(vis,0,sizeof(vis)); f=0; for(int i=1;i<=n;++i){ if(a[i]-'0'==f){ } else{ anss++; if(!vis[i]) vis[i]=1; if(vis[i-1]) anss--; } f^=1; } ans=min(ans,anss); printf("%d\n",ans);

C. Chef Monocarp

題意:一分鐘只能出一個餐,一開始所有餐都在烤爐裡,每次出餐貢獻+|t[i]−T|(T為當前時間),問讓總貢獻最小的方法。
(注:出餐時間不一定連續。

很顯然是一個dp題,但是我沒想到方程怎麼寫。

dp[i][j]表示第i號餐在j時間出來的最優解。

先排個序,因為時間是線性增長的,t[i]線性增長更優。

程式碼來自一位dalao

int dp[270][270*2],a[270],t,n;
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;++i)    scanf("%d",&a[i]);
        memset(dp,0x7f,sizeof(dp));
        for(int i=0;i<=2*n;++i)    dp[0][i]=0;
        sort(a+1,a+1+n);
        for(int i=1;i<=n;++i){
            for(int j=i-1;j<=2*n;++j){
                for(int k=j+1;k<=2*n;++k){
                    dp[i][k]=min(dp[i][k],dp[i-1][j]+abs(a[i]-k));
                } 
            } 
        }
        int ans=inf;
        for(int i=n;i<=2*n;++i)    ans=min(ans,dp[n][i]);
        printf("%d\n",ans);
    }
    return 0;
} 

D. Minimal Height Tree

題意:給定樹的bfs序,對任意節點的子節點按升序排列,問最小高度是多少?

如果理解不了,我就來畫個圖吧。

兩個都是1 4 5 2 3的遍歷順序,明顯第一幅圖更優。

先看一下程式碼

int t,a[200007],q[200007],p,n;    //q記錄每層的個數
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        memset(q,0,sizeof(q));
        q[0]=1;p=1;
        for(int i=1;i<=n;++i)    scanf("%d",&a[i]);
        for(int i=2;i<=n;++i){
            if(a[i]>a[i-1]){    //升序就加入當前層
                q[p]++;
            }
            else if(q[p-1]>1){   //看一下上一層子結點個數大於1,掛到上層那個點
                q[p-1]--;
                q[p]++;
            }
            else if(q[p-1]==1){   //上層個數==1,說明,上層已經沒有空間加了
                p++;
                q[p]++;
            }
        }
        printf("%d\n",p);
    }
    return 0;
} 

還理解不了就對圖跑一遍,記住節點的子結點都必須升序。