2021.8.4考試總結[NOIP模擬30]
阿新 • • 發佈:2021-08-04
T1毛一琛 T2毛二琛 T3毛三琛
T1 毛衣襯
將合法子集分為兩個和相等的集合。
暴力列舉每個元素是否被選,放在哪種集合,複雜度$O(3^n)$。考慮$\textit{meet in the middle}$。
將全集等分分為兩部分分別考慮,先$O(3^{\frac{n}{2}})$列舉前一部分的所有情況,記錄兩個集合的差所對應的狀態,然後同樣$O(3^{\frac{n}{2}})$列舉後一部分,與前一部分進行匹配即可。
$\textit{meet in the middle}$真還挺神的,以後做題要多考慮。
$code:$
1 #include<bits/stdc++.h> 2 #define int long long 3T1#define rin register signed 4 #define pb push_back 5 using namespace std; 6 const int NN=25; 7 int n,m[NN],tot,mx,mid,ans,cnt; 8 bool vis[10000005]; 9 map<int,int>tmp; 10 vector<int>sta[10000005]; 11 inline int read(){ 12 int x=0,f=1; char ch=getchar(); 13 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 14 while(ch<='9'&&ch>='0'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 15 return x*f; 16 } 17 inline void write(int x){ 18 char ch[20]; int len=0; 19 if(x<0) x=~x+1, putchar('-'); 20 do{ 21 ch[len++]=x%10+(1<<5)+(1<<4); 22 x/=10; 23 }while(x); 24 for(rin i=len-1;i>=0;--i) putchar(ch[i]); 25 } 26 void ldfs(int s,int ls,int rs,int st){ 27 if(s>mid){ 28 if(!tmp[ls-rs]) tmp[ls-rs]=++cnt; 29 int now=tmp[ls-rs]; 30 sta[now].pb(st); 31 return; 32 } 33 ldfs(s+1,ls,rs,st); 34 ldfs(s+1,ls+m[s],rs,st|(1<<(s-1))); 35 ldfs(s+1,ls,rs+m[s],st|(1<<(s-1))); 36 } 37 void rdfs(int s,int ls,int rs,int st){ 38 if(s>n){ 39 if(tmp.find(rs-ls)==tmp.end()) return; 40 int now=tmp[rs-ls]; 41 for(int i=0;i<sta[now].size();i++){ 42 if(st&sta[now][i]) continue; 43 if(!(st|sta[now][i])) continue; 44 if(!vis[st|sta[now][i]]) vis[st|sta[now][i]]=1, ++ans; 45 } 46 return; 47 } 48 rdfs(s+1,ls,rs,st); 49 rdfs(s+1,ls+m[s],rs,st|(1<<(s-1))); 50 rdfs(s+1,ls,rs+m[s],st|(1<<(s-1))); 51 } 52 signed main(){ 53 n=read(); tot=(1<<n)-1; mid=n>>1; 54 for(rin i=1;i<=n;i++) m[i]=read(); 55 ldfs(1,0,0,0); rdfs(mid+1,0,0,0); 56 write(ans); putchar('\n'); 57 return 0; 58 }
T2 貓兒沉
考場上完全不會,打了$\text{next_permutation}$