u1s1,我的代码在洛谷上只能拿88pts,但在其他OJ上能过,所以如果你想在洛谷上通过这道题那请出门左转。
这道题看题面和数据范围就知道是搜索加一些神奇的剪枝。
我一开始的想法是按人枚举,但发现这样连裸的搜索都很难写,所以我转化了一下思路,枚举比赛(即用 ( x , y ) 来表示比赛双方)。
这样的话裸的搜索就很好写了,分 y = n 和 y != n 两种情况讨论就好了。
接下来我们来思考几个剪枝:
1. 如果当前某一方加分后超过最终分数,可以剪枝。
2. 如果某一方即使后面的比赛全赢也无法到达最终分数,可以剪枝。
3. 如果当前是某个人的最后一场比赛,可以直接推出结果。
然后一一实现就好啦~
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define int long long #define maxn 10 #define rep(i,s,e) for(register int i=s;i<=e;++i) #define dwn(i,s,e) for(register int i=s;i>=e;--i) using namespace std; inline int read() { int x=0,f=1; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();} return f*x; } inline void write(int x) { if(x<0){putchar('-');x=-x;} if(x>9)write(x/10); putchar(x%10+'0'); } int n,ans; int s[maxn],f[maxn]; inline bool check() { rep(i,1,n) if(s[i]!=f[i]) return 0; return 1; } void dfs(int x,int y) { if(x==n) if(check()==1) {++ans; return;} if(s[x]+3*(n-y+1)<f[x]) return;//剪枝一 if(y==n)//剪枝二 { if(f[x]-s[x]==1) { s[x]++;s[y]++; dfs(x+1,x+2); s[x]--;s[y]--; } else if(f[x]-s[x]==0) { s[y]+=3; dfs(x+1,x+2); s[y]-=3; } else if(f[x]-s[x]==3) { s[x]+=3; dfs(x+1,x+2); s[x]-=3; } } if(s[x]+3<=f[x])//剪枝三 { s[x]+=3; dfs(x,y+1); s[x]-=3; } if(s[y]+3<=f[y])//剪枝三 { s[y]+=3; dfs(x,y+1); s[y]-=3; } if(s[x]+1<=f[x]&&s[y]+1<=f[y])//剪枝三 { s[x]++;s[y]++; dfs(x,y+1); s[x]--;s[y]--; } } signed main() { n=read(); rep(i,1,n) f[i]=read(); dfs(1,2); write(ans); return 0; }