传送门
解析
dfs暴力枚举即可
这题的重点是如何剪枝
不难发现,随着不断处理,纸条只会越来越短,且所有数字总加和不变
我一开始想到了2个条件:
1.当前长度比理想纸条小,return;
2.总加和与理想纸条不等,直接输出N
但是这样仍是O(n!)的级别,得到了80分
后来又想到:
反转之后对后一半的与反转前对前一半的折叠是等效的,所以只需要递归一半的长度即可
从而通过本题
代码
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <string>
#include <queue>
#include <string>
#include<map>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a));
using namespace std;
const int N=50;
const int M=1e9;
int n,m,mod;
int a[N],b[N];
int save[N][N],save2[N][N];
int flag;
void memory(int l){for(int i=0;i<=a[0];i++) save[l][i]=a[i];
}
void restore(int l){for(int i=0;i<=save[l][0];i++) a[i]=save[l][i];
}
void fold(int p){memory(a[0]);int x=0,l=a[0];if(p<=a[0]/2){for(int i=save[l][0];i>=p+p+1;i--) a[++x]=save[l][i];for(int i=1;i<=p;i++) a[++x]=save[l][i]+save[l][p+p-i+1];a[0]-=p;}else{for(int i=1;i<=2*p-a[0];i++) a[++x]=save[l][i];for(int i=2*p-save[l][0]+1;i<=p;i++) a[++x]=save[l][i]+save[l][save[l][0]-(i-(2*p-save[l][0]))+1];a[0]-=(a[0]-p);}return;
}
void memory2(int l){for(int i=0;i<=a[0];i++) save2[l][i]=a[i];
}
void restore2(int l){for(int i=0;i<=save2[l][0];i++) a[i]=save2[l][i];
}
void fanzhuan(){memory2(a[0]);for(int i=1;i<=a[0];i++) a[i]=save2[a[0]][save2[a[0]][0]-i+1];
}
bool judge(){for(int i=0;i<=b[0];i++){if(a[i]!=b[i]) return false;}return true;
}
void print(){for(int i=1;i<=a[0];i++) printf("%d ",a[i]);printf("\n");
}
bool jd(){int pd[N]={},ok[N]={};for(int i=1;i<=a[0];i++) pd[i]=a[i];sort(pd+1,pd+1+a[0]);for(int i=1;i<=b[0];i++) ok[i]=b[i];sort(ok+1,ok+1+b[0]);
// for(int i=1;i<=b[0];i++){
// printf("b=%d a=%d\n",ok[i],pd[i]);
// }for(int i=1;i<=b[0];i++){if(ok[i]<pd[i]) return false;}return true;
}
void dfs(){
// print();if(flag) return;if(a[0]<b[0]) return;
// if(!jd()) return;int l=a[0];if(a[0]==b[0]){if(judge()){printf("S\n");flag=1;return;}fanzhuan();if(judge()){printf("S\n");flag=1;}restore2(l);return;}for(int i=1;i<=a[0]/2;i++){fold(i);dfs();if(flag) return;restore(l);}fanzhuan();for(int i=1;i<=a[0]/2;i++){fold(i);dfs();if(flag) return;restore(l);}restore2(l);return;
}
int main(){while(scanf("%d",&n)==1){flag=0;int tot=0;mem(a,0);mem(b,0);for(int i=1;i<=n;i++) mem(save[i],0);for(int i=1;i<=n;i++){scanf("%d",&a[i]);tot+=a[i];}a[0]=n;scanf("%d",&m);for(int i=1;i<=m;i++){scanf("%d",&b[i]);tot-=b[i];}b[0]=m;if(m>n||tot!=0){printf("N\n");continue;}dfs();if(!flag) printf("N\n");}return 0;
}