T1 玩具
题目读错意思直接报零。。。
拼接方式没读懂以为是个数学题,用卡特兰数,可是的确想多了
数据范围表达出你怎么暴力都行,选择$n^3,dp$
相当于一片森林,每次多加一条边就合并成一棵树
在$dp$过程中统计合并的树的信息再算上贡献就行
T2 y
因为上次考试做过的v是一个将状态提取到数组里
这次为了暴力用了同样的方法
将状态枚举,提取出来后进行$XIN$队
1 #include<bits/stdc++.h>//状压思想枚举每一种状态,然后爆搜 2 #define int long long 3 using namespace std; 4 int n,m,d;bool flag;short pre[21]; 5 struct SNOW{int from,to,val,next;};SNOW e[1000000]; int head[1000000],rp; 6 inline void add(int x,int y,int z){e[++rp]=(SNOW){x,y,z,head[x]};head[x]=rp;} 7 inline void dfs(int x,int cnt){ 8 if(!cnt){flag=1;return;} 9 for(int i=head[x];i;i=e[i].next) 10 if(e[i].val==pre[cnt]) dfs(e[i].to,cnt-1); 11 return; 12 } 13 namespace WSN{ 14 inline int main(){ 15 scanf("%lld%lld%lld",&n,&m,&d); int tmp=0; 16 for(int i=1,u,v,c;i<=m;i++){ 17 scanf("%lld%lld%lld",&u,&v,&c),add(u,v,c),add(v,u,c); 18 if(!c) tmp++; 19 } 20 if(tmp==m){ 21 if(m==1) {cout<<0<<endl;return 0;} 22 else {cout<<1<<endl;return 0;} 23 } 24 int mzs=1<<d,ans=0; 25 for(int i=0;i<mzs;i++){ 26 int st=i; flag=0; 27 for(int j=1;j<=d;j++) pre[j]=(st&1),st>>=1; 28 dfs(1,d); if(flag) ans++; 29 } 30 printf("%lld\n",ans); 31 return 0; 32 } 33 } 34 signed main(){return WSN::main();}View Code
正解是一个叫$Meet In the Middle$的东西,其实可以很简单的理解为起点终点向中间去碰数。。
就分别统计以1到它长度为$len/2$的所有状态,距离1为$d$的点到中间$d/2$的所有状态
再依次拼接,查看有没有重复计算的总状态即可
复杂度最高的在于枚举状态,他分成$d/2$的两次枚举,比直接枚举$d$快了不知道多少。。
1 #include<bits/stdc++.h>//状压思想枚举每一种状态,然后爆搜 2 #define int long long 3 using namespace std; 4 int n,m,d,len; 5 bool vis[1<<21]; 6 vector<int> vc1[91],vc2[91]; 7 bool f1[91][91][1025],f2[91][91][1025]; 8 struct SNOW{int from,to,val,next;};SNOW e[1000000]; int head[1000000],rp; 9 inline void add(int x,int y,int z){e[++rp]=(SNOW){x,y,z,head[x]};head[x]=rp;} 10 namespace WSN{ 11 inline int main(){ 12 scanf("%lld%lld%lld",&n,&m,&d); int ans=0; 13 for(int i=1,u,v,c;i<=m;i++)scanf("%lld%lld%lld",&u,&v,&c),add(u,v,c),add(v,u,c); 14 len=d>>1; f1[0][1][0]=1; 15 for(int i=1;i<=len;i++) for(int j=1;j<=n;j++) for(int k=0;k<(1<<i);k++) 16 for(int u=head[j];u;u=e[u].next) f1[i][e[u].to][k<<1|e[u].val]|=f1[i-1][j][k]; 17 int lenn; 18 if(d%2!=0) lenn=len+1; 19 else lenn=len; 20 for(int i=1;i<=n;i++) f2[0][i][0]=1; 21 for(int i=1;i<=lenn;i++) for(int j=1;j<=n;j++) for(int k=0;k<(1<<i);k++) 22 for(int u=head[j];u;u=e[u].next) f2[i][e[u].to][k<<1|e[u].val]|=f2[i-1][j][k]; 23 for(int i=1;i<=n;i++){ 24 for(int k=0;k<(1<<len);k++) if(f1[len][i][k]) vc1[i].push_back(k); 25 for(int k=0;k<(1<<lenn);k++) if(f2[lenn][i][k]) vc2[i].push_back(k); 26 } 27 for(int i=1;i<=n;i++) for(int j=0;j<vc1[i].size();j++) for(int k=0;k<vc2[i].size();k++) 28 if(!vis[(vc1[i][j]<<lenn|vc2[i][k])]) ans++,vis[(vc1[i][j]<<lenn|vc2[i][k])]++; 29 printf("%lld\n",ans); 30 return 0; 31 } 32 } 33 signed main(){return WSN::main();}优秀的缩进
T3 z
超级麻烦的一道题,现在还没改出来,先沽了~~~