[CQOI2009] 循环赛 - 暴力出奇迹
来源:互联网 发布:java图形输出的编程题 编辑:程序博客网 时间:2024/05/15 15:14
题目描述
n支队伍打比赛,每两支队伍恰好比赛一场。平局时各得1分,而有胜负时胜者3分,负者0分。
假设三支队伍得分分别为3, 3, 3,则可能有两种情况:
给出n支队伍的最终得分(即所有比赛均已结束),统计有多少种可能的分数表。
输入格式
第一行包含一个正整数n,队伍的个数。第二行包含n个非负整数,即每支队伍的得分。
输出格式
输出仅一行,即可能的分数表数目。保证至少存在一个可能的分数表。
样例数据
样例输入
样例数据#1
3
3 3 3
样例数据#2
2
0 3
样例数据#3
3
4 1 2
样例数据#4
6
5 6 7 7 8 8
样例输出
样例数据#1
2
样例数据#2
1
样例数据#3
1
样例数据#4
121
数据规模
题目分析
麻烦的搜索题,加了无数个剪枝和优化终于过了。。。
不过比起斗地主、Mayan游戏、素数方阵这些厉害的搜索题来说还算轻松
数据很良心,纯粹爆搜可以得88分左右
剪枝1:
可行性剪枝,如果当前队伍剩下的全赢也不能达到目标或当前队伍已经超过了目标,剪。
优化2:
由于棋盘是类对称的,故只需要枚举一半的棋盘
优化3:
因为平局总分数+2,非平局总分数+3,故可以列方程求出平局与非平局的数量,作为资源分配到搜索中
剪枝4:
不必搜索出情况后检查可行性,直接计算出每一个队伍最后一场比赛的得分
优化5:
大幅度提高时间效率:Hash判重。将剩余状态的方案用Hash保存,下一次直接调用。(有点碰运气的成分)
源代码
#include<algorithm>#include<iostream>#include<iomanip>#include<cstring>#include<cstdlib>#include<vector>#include<cstdio>#include<cmath>#include<queue>using namespace std;inline const int Get_Int() { int num=0,bj=1; char x=getchar(); while(x<'0'||x>'9') { if(x=='-')bj=-1; x=getchar(); } while(x>='0'&&x<='9') { num=num*10+x-'0'; x=getchar(); } return num*bj;}typedef long long LL;int n,Remain[15],vst[9][174109],Hash[9][174109];LL Dfs(int x,int y,LL Win,LL Equal) { if(y==1) { //Hash判重 int tmp[15]= {0},num=0; for(int i=1; i<=n-(x-1); i++)tmp[i]=Remain[(x-1)+i]; sort(tmp+1,tmp+n-(x-1)+1); for(int i=1; i<=n-(x-1); i++)num=(num*23+tmp[i])%174107; if(!vst[n-(x-1)][num]) { Hash[n-(x-1)][num]=Dfs(x,x+1,Win,Equal); vst[n-(x-1)][num]=1; } return Hash[n-(x-1)][num]; } if(x>=y)return Dfs(x,x+1,Win,Equal); //只枚举一半棋盘 if(x==n&&y==n+1)return 1; //找到一个可能性 if((n-y+1)*3<Remain[x]||Remain[x]<0)return 0; //可行性剪枝 int Nextx=x,Nexty=y; LL sum=0; if(Nexty==n) { //最后一个位置 :计算得出 if(Remain[x]==1&&Equal>=1) { Remain[y]--; sum+=Dfs(x+1,1,Win,Equal-1); Remain[y]++; } else if(Remain[x]==0&&Win>=1) { Remain[y]-=3; sum+=Dfs(x+1,1,Win-1,Equal); Remain[y]+=3; } else if(Remain[x]==3&&Win>=1)sum+=Dfs(x+1,1,Win-1,Equal); return sum; } else Nexty++; if(Equal>=1&&Remain[x]>=1&&Remain[y]>=1) { Remain[x]--; Remain[y]--; sum+=Dfs(Nextx,Nexty,Win,Equal-1); Remain[x]++; Remain[y]++; } if(Win>=1) { if(Remain[x]>=3) { Remain[x]-=3; sum+=Dfs(Nextx,Nexty,Win-1,Equal); Remain[x]+=3; } if(Remain[y]>=3) { Remain[y]-=3; sum+=Dfs(Nextx,Nexty,Win-1,Equal); Remain[y]+=3; } } return sum;}LL sum=0,Win,Equal;int main() { n=Get_Int(); for(int i=1; i<=n; i++) { Remain[i]=Get_Int(); sum+=Remain[i]; } Win=abs(sum-(n*(n-1))); //赢或输的总次数 Equal=abs((n*(n-1)/2)-Win); //平局总次数 printf("%lld\n",Dfs(1,2,Win,Equal)); return 0;}
0 0
- [CQOI2009] 循环赛 - 暴力出奇迹
- 暴力出奇迹!
- 暴力出奇迹
- F - 暴力出奇迹
- bzoj1306: [CQOI2009]match循环赛
- 1306: [CQOI2009]match循环赛
- bzoj1306 [CQOI2009]match循环赛
- bzoj3140 hnoi2013 消毒(暴力出奇迹)
- BZOJ 1306: [CQOI2009]match循环赛
- bzoj 1306 [CQOI2009]match循环赛
- BZOJ P1306 [CQOI2009]match循环赛
- Codeforces 452B 4-point polyline (暴力出奇迹)
- 循环数组最大子段和 ~~~~暴力出奇迹
- bzoj1770 USACO NOV09 GOLD 灯(暴力出奇迹)
- bzoj1853【scoi2010】幸运数字(暴力出奇迹)
- BZOJ 1306: [CQOI2009]match循环赛 爆搜,剪枝
- 2016华为软件精英挑战赛:低级案例---暴力出奇迹(一)
- 51nod 1001 和为k的数对 暴力出奇迹
- springmvc+shiro
- 关于小白练级
- 【issue analysis】嵌入式系统软件书写卡顿问题
- Linux命令使用以及vim编辑器的使用
- 微服务(Microservice)那点事
- [CQOI2009] 循环赛 - 暴力出奇迹
- Android Studio常用快捷键
- Java中矩阵运算(math3的使用)
- centos+php7.1+apache
- 数据库程序
- 最大公约数&&最小公倍数C语言
- 事务特性和隔离级别
- [Java]读取文件方法大全
- 图像拼接(三):OpenCV同时打开两个摄像头捕获视频