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 值而已,沒啥好說的,跳過吧。