8.31 上午 becoder 模擬賽總結 & 題解

tkdqmx發表於2024-09-03

T1 四個質數的和

賽場親測搜尋+小剪枝可以得到 70pts。

考慮 $O(p(V)^2)$列舉任意兩個質數的和,其中 $p(V)$ 表示 $V$ 以內質數的個數。

然後開個陣列記錄下對於每種和的記錄有多少種情況,查詢時 for 迴圈掃一遍即可,詳見程式碼。

複雜度去掉質數篩 $O(p(V)^2+tn)$,程式碼貼在下面(100pts):

#define N 100005
int t,n,cnt,pr[N];
long long ans,prs[N<<1];
int main(){
   //pr 儲存的是 V 以內的質數
   for(int i=1;i<=cnt;i++)
        for(int j=1;j<=cnt;j++)
            prs[pr[i]+pr[j]]++;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n),ans=0;
        for(int i=1;i<n;i++)  ans+=prs[i]*prs[n-i];
        printf("%lld\n",ans);
    }
}

T2 匹配最大異或

位運算的題我們考慮分離二進位制下的每一位,這道題使用的是分治。

分治從 $[0,2^{m-1})$ 開始,這樣我們可以保證當前列舉的這一層前面的二進位制位都是相同的。

所以我們考慮當前列舉到的這一位中的兩種情況:

第一種,$a$ 陣列的這一位上的值都相同,此時這一位就無法對答案產生影響。

這個時候就要求對於這一位分別是 $0,1$ 且其它位相同的兩個數所選定的 $p$ 值必須相同,才能保證這兩個數都能取得最大取值。

第二種,$a$ 陣列的這一位上的值有 $0$ 也有 $1$這個時候這一位上是 $0$ 就必須選 $1$,反之亦然。

這個時候就要求對於這一位分別是 $0,1$ 且其它位相同的兩個數所選定的 $p$ 值必須不同,才能保證這兩個數都能取得最大取值。

以上兩種情況已經涵蓋了全部,所以中途出現的其它情況直接返回 $0$ 即可。

時間複雜度 $O(n \log n)$,程式碼如下(100pts):

long long solve(int l,int r){
    if(l==r)  return 1;
    int cnt=0,mid=(l+r)>>1;
    for(int i=l;i<=mid;i++)  cnt+=(p[i]==p[i+mid-l+1]);
    if(cnt==mid-l+1)  return (solve(l,mid)<<1)%mod;
    if(!cnt)  return (solve(l,mid)*solve(mid+1,r))%mod;
    return 0;
}
int main(){solve(1,(1<<m)-1);}

T3 蟲食算

我程式碼在洛谷交是 AC 的,但是交 becoder 卡了好久死活 90pts 過不去。

這道題其實有高斯消元的正解,但是我們不管,考慮搜尋+剪枝。

正常的搜尋大家都會,直接 $O(n!)$ 列舉每一位上的數即可,這樣就已經可以過掉 30pts 的資料了,然後我們考慮怎麼剪枝。

搜尋的時候我們選擇從最低位開始進行搜尋,因為這樣我們能在搜尋中直接把進位給算出來,就可以少考慮很多情況。

對於每一位我們直接列舉三個字母對應值,原本有就跳過,然後如果三個字母加上進位滿足條件,就帶著這個值往下搜尋。

列舉字母值的時候我們則選擇從大到小列舉,因為最高位是不能進位的,所以能進位的就優先放到低位。

透過如上程式碼就可以在洛谷的評測環境透過了,但是 becoder 的評測機不行,還要剪枝,但我不會了,希望來兩個好心人幫我剪

程式碼如下(becoder 90pts,Luogu 100pts):

char a[30],b[30],c[30];
int n,f[30],go[30],s[100];
int gmod(int x,int &y){return x>=n?(y=1,x-n):(y=0,x);}
void dfs(int x){
    if(!x){
        for(int i=0;i<n;i++)  printf("%d ",s['A'+i]);
        exit(0);
    }
    for(int i=n-1,fl1=0;i>=0;i--){
        if(s[a[x]]!=-1)  fl1=1;
        else if(f[i])  continue;
        if(!fl1)  f[i]=1,s[a[x]]=i;
        for(int j=n-1,fl2=0;j>=0;j--){
            if(s[b[x]]!=-1)  fl2=1;
            else if(f[j])  continue;
            if(!fl2)  f[j]=1,s[b[x]]=j;
            int tmp=gmod(s[a[x]]+s[b[x]]+go[x+1],go[x]);
            if(s[c[x]]!=-1&&tmp==s[c[x]])  dfs(x-1);
            if(s[c[x]]==-1&&!f[tmp])  s[c[x]]=tmp,f[tmp]=1,dfs(x-1),f[tmp]=0,s[c[x]]=-1;
            if(fl2)  break;f[j]=0,s[b[x]]=-1;
        }
        if(fl1)  break;f[i]=0,s[a[x]]=-1;
    }
}
int main(){scanf("%d%s%s%s",&n,a+1,b+1,c+1),fill(s,s+100,-1),dfs(n);}

T4 染色相鄰的邊

NOIP 鞏固練習 5,NOI2011 輕重邊。

只不過輸出的時候換成了用兩點間的路徑長減去原來的 ans 值而已,沒啥好說的,跳過吧。