纪中20日c组模拟赛T1 2121. 简单游戏
T1 2121. 简单游戏
(File IO): input:easy.in output:easy.out
时间限制: 1000 ms 空间限制: 262144 KB 具体限制
题目描述
输入
输出
样例输入
4 16
3 9
0 0
样例输出
3 1 2 4
1 3 2 对样例解释:
开始排列: 3 1 2 4
第一次操作:3+1=4 1+2=3 2+4=6
得到: 4 3 6
第二次得到: 7 9
最后就是: 16
数据范围限制
对于30%的数据,保证该组里的每个N都不超过10。
对于100%的数据,保证有每个N不超过20,且每组数据的个数不超过10。
Solution
首先可以发现,对于一个长度为n的排列,经过了n-1次邻项相加后,第i项被加了C(n-1,i)次(二项式定理).
所以可以先预处理杨辉三角形。
Algorithm1
使用next_permutation方便的计算地排列
但是没有剪枝...很慢的
Code1
简单的垃圾代码
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<vector>
#include<queue>
#define IL inline
using namespace std;
int tria[][]={
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
};
//triangle
int ans;
int arr[],t,n;
IL int read()
{
char ch;int x=;
ch=getchar();
while(ch<''||ch>'') ch=getchar();
while(ch>=''&&ch<='') x=(x<<)+(x<<)+(ch^),ch=getchar();
return x;
}
int main()
{
freopen("easy.in","r",stdin);
freopen("easy.out","w",stdout);
n=read();
t=read();
do{
for(int i=;i<=n;i++)
arr[i]=i;
do{
ans=;
int i;
for(i=;i<=n&&ans<=t;i++)
ans+=arr[i]*tria[n][i];
if(ans==t&&i>n){
for(int j=;j<=n;j++){
printf("%d",arr[j]);
if(j<n) printf(" ");
}
cout<<endl;
break;
}
}while(next_permutation(arr+,arr+n+));
n=read();
t=read();
}while(n!=||t!=);
return ;
}
Code1
Algorithm2
使用dfs,对每一位进行判断,同时标记use(是否使用过此数)
这比next_permutation好在可以尽情剪枝——只要你能想到
Code2
这是剪枝1:如果当前的和(前depth个数的和)已经超过了t,就跳出。
也可以把
if(sum>t) return;
放到for循环里(这不是废话吗)
可以减少一点分支
按照题解上的说法,这样子只有40分(果然……)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<vector>
#include<queue>
#define IL inline
using namespace std;
int tria[][]={
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
};
int use[];
int ans;
int arr[],t,n;
IL int read()
{
char ch;int x=;
ch=getchar();
while(ch<''||ch>'') ch=getchar();
while(ch>=''&&ch<='') x=(x<<)+(x<<)+(ch^),ch=getchar();
return x;
}
bool succ=;
IL void dfs(int depth,int sum)
{
if(sum>t) return;
if(succ) return;
if(depth==n){
if(sum==t)
{
succ=;
for(int j=;j<=n;j++){
printf("%d",arr[j]);
if(j<n) printf(" ");
}
printf("\n");
}
return;
}
for(int i=;i<=n;i++)
{
if(!use[i])
{
use[i]=;
arr[depth+]=i;
dfs(depth+,sum+i*tria[n][depth+]);
arr[depth+]=;
use[i]=;
}
}
}
int main()
{
// freopen("easy.in","r",stdin);
// freopen("easy.out","w",stdout);
n=read();
t=read();
do{
succ=;
dfs(,);
n=read();
t=read();
}while(n!=||t!=);
return ;
}
Algorithm3
这是剪枝2:
由于杨辉三角形有对称性
比如,枚举到 2 4 1 3 时,其sum(邻项合并后的结果)会与 2 1 4 3 相同
那么可以加入以下判断:
if(depth>(n/) && i<arr[n-depth]) continue;
代码翻译
如果当前要枚举的数即将放的位置超过了总长度的一半,且即将枚举的数值i小于与它关于这个二项式对称的那一项,那就说明这两项如果调换,总值不会发生变化,那么就不考虑这种情况。
这句话真长……
Code3
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<vector>
#include<queue>
#define IL inline
using namespace std;
int tria[][]={
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
};
int use[];
int arr[],t,n;
IL int read()
{
char ch;int x=;
ch=getchar();
while(ch<''||ch>'') ch=getchar();
while(ch>=''&&ch<='') x=(x<<)+(x<<)+(ch^),ch=getchar();
return x;
}
bool succ=;
IL void dfs(int depth,int sum)
{
if(succ) return;
if(depth==n){
if(sum==t)
{
succ=;
for(int j=;j<=n;j++){
printf("%d",arr[j]);
if(j<n) printf(" ");
}
printf("\n");
}
return;
}
for(int i=;i<=n;i++)
{
if(!use[i])
{
if(depth>(n/) && i<arr[n-depth]) continue;
if(sum+i*tria[n][depth+]>t) continue;
use[i]=;
arr[depth+]=i;
dfs(depth+,sum+i*tria[n][depth+]);
arr[depth+]=;
use[i]=;
}
}
}
int main()
{
// freopen("easy.in","r",stdin);
// freopen("easy.out","w",stdout);
n=read();
t=read();
do{
succ=;
dfs(,);
n=read();
t=read();
}while(n!=||t!=);
return ;
}
Code3
好的,果然如题解所说,这个剪枝并不能加分。
Algorithm4
这是剪枝3:枚举前,就当前还未使用的数字来讲,可以将它们重新排序,对应还没使用的系数,可以算出已选择的数字不变的情况下,让之后几个数排列组合,再乘以对应系数的和的最大值与最小值。
貌似我讲的不太清楚。
当枚举到第X个数时,剩余的N-X个数,与剩余的N-X个系数一一对应,让大数和大系数相乘,小数和小系数相乘可以得到最大值,让大数和小系数相乘,小数和大系数相乘可以得到最小值,如果剩余的值不在这个范围内,就不要搜下去,这样可以大大优化。
举个栗子
若N=4,T=16:
当枚举arr[1]=1时,剩余16-1*1=15,剩余的未放置的数为2,3,4,剩余的系数为1,3,3,这样最大值为4*3+3*3+2*1=23,最小值为4*1+3*3+2*3=19,都超过了15,所以第一个数不能选1。
Code4
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<vector>
#include<queue>
#define IL inline
using namespace std;
int tria[][]={
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
};
int use[];
int tarr[],ttria[];
int arr[],t,n;
IL int read()
{
char ch;int x=;
ch=getchar();
while(ch<''||ch>'') ch=getchar();
while(ch>=''&&ch<='') x=(x<<)+(x<<)+(ch^),ch=getchar();
return x;
}
bool succ=;
IL void dfs(int depth,int sum)
{
if(succ) return;
if(depth==n){
if(sum==t)
{
succ=;
for(int j=;j<=n;j++){
printf("%d",arr[j]);
if(j<n) printf(" ");
}
printf("\n");
}
return;
} int s=;
for(int i=;i<=n;i++)
{
if(use[i]) continue;
tarr[++s]=i;
}
for(int i=depth+;i<=n;i++)
ttria[i-depth]=tria[n][i];
sort(tarr+,tarr+s+);
sort(ttria+,ttria+s+);
int maxs=,mins=;
for(int i=;i<=s;i++)
{
maxs+=tarr[i]*ttria[i];
mins+=tarr[i]*ttria[s-i+];
}
if(t<mins+sum||t>maxs+sum) return; for(int i=;i<=n;i++)
{
if(!use[i])
{
if(depth>(n/) && i<arr[n-depth]) continue;
if(sum+i*tria[n][depth+]>t) continue;
use[i]=;
arr[depth+]=i;
dfs(depth+,sum+i*tria[n][depth+]);
arr[depth+]=;
use[i]=;
}
}
}
int main()
{
// freopen("easy.in","r",stdin);
// freopen("easy.out","w",stdout);
n=read();
t=read();
do{
succ=;
dfs(,);
n=read();
t=read();
}while(n!=||t!=);
return ;
}
Impression
好辛苦呀~~~
纪中20日c组模拟赛T1 2121. 简单游戏的更多相关文章
- 纪中20日c组模拟赛
赛后感想 多写点东西总是好的,但是在最后,算法就不要改动了(就这样我少了10分) 题解 T1 2121. 简单游戏 T2 2122. 幸运票
- 纪中18日c组模拟赛
T2 GMOJ2127. 电子表格 (File IO): input:excel.in output:excel.out 时间限制: 1000 ms 空间限制: 262144 KB 具体限制 ...
- 纪中21日c组模拟赛
AWSL AWSL AWSL AWSL AWSL AWSL AWSL AWSL AWSL AWSL AWSL AWSL AWSL AWSL AWSL AWSL 题解传送 T1 ...
- 纪中20日c组T2 2122. 【2016-12-31普及组模拟】幸运票
2122. 幸运票 (File IO): input:tickets.in output:tickets.out 时间限制: 1000 ms 空间限制: 262144 KB 具体限制 Goto P ...
- 洛谷P1880 [NOI1995]石子合并 纪中21日c组T4 2119. 【2016-12-30普及组模拟】环状石子归并
洛谷P1880 石子合并 纪中2119. 环状石子归并 洛谷传送门 题目描述1 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石 ...
- 纪中23日c组T2 2159. 【2017.7.11普及】max 洛谷P1249 最大乘积
纪中2159. max 洛谷P1249 最大乘积 说明:这两题基本完全相同,故放在一起写题解 纪中2159. max (File IO): input:max.in output:max.out 时间 ...
- 纪中23日c组T3 2161. 【2017.7.11普及】围攻 斐波那契数列
2161. 围攻 (File IO): input:siege.in output:siege.out 时间限制: 1000 ms 空间限制: 262144 KB 具体限制 Goto Prob ...
- 纪中21日c组T2 2117. 【2016-12-30普及组模拟】台风
2117. 台风 (File IO): input:storm.in output:storm.out 时间限制: 1000 ms 空间限制: 262144 KB 具体限制 Goto Proble ...
- 纪中21日c组T1 1575. 二叉树
1575. 二叉树 (File IO): input:tree.in output:tree.out 时间限制: 1000 ms 空间限制: 262144 KB 具体限制 Goto Probl ...
随机推荐
- 3万字总结,Mysql优化之精髓
本文知识点较多,篇幅较长,请耐心学习 MySQL已经成为时下关系型数据库产品的中坚力量,备受互联网大厂的青睐,出门面试想进BAT,想拿高工资,不会点MySQL优化知识,拿offer的成功率会大大下降. ...
- cpp二进制与整数之间的转换的几种方式记录
PS: 程序为cpp代码,最重要理解操作. 方法一: n进制方法,也可以解决转换为其他进制问题. /*将整数转化为二进制的string 输出*/ string convert(int num) { s ...
- pyhon学习Day18--继承
[知识点] 面向对象的三大特性:继承.多态.封装 [继承] (1)继承:class Person(Animal): ——括号里的:父类,基类,超类 括号外的:子类,派生类 class Animal ...
- SpringBoot之切面AOP
SpringBoot提供了强大AOP支持,我们前面讲解过AOP面向切面,所以这里具体AOP原理就补具体介绍: AOP切面主要是切方法,我们一般搞一些日志分析和事务操作,要用到切面,类似拦截器: @As ...
- 了解EBP指针
在寄存器里面有很多寄存器虽然他们的功能和使用没有任何的区别,但是在长期的编程和使用中,在程序员习惯中已经默认的给每个寄存器赋上了特殊的含义,比如:EAX一般用来做返回值,ECX用于记数等等.在win3 ...
- 消息中间件面试题31道RabbitMQ+ActiveMQ+Kafka
消息中间件面试题31道RabbitMQ+ActiveMQ+Kafka 前言 文章开始前,我们先了解一下什么是消息中间件? 什么是中间件? 非底层操作系统软件,非业务应用软件,不是直接给最终用户使用的, ...
- Android Spinner 下拉框简单应用 详细注解
目录 Android Spinner 代码部分 Spinner代码介绍 核心代码 说在最后 @ Android Spinner Spinner 提供下拉列表式的输入方式,该方法可以有效节省手机屏幕上的 ...
- react-native当使用antd-mobile出现View config not found for name div
1.npm uninstall antd-mobile 2.npm uninstall react 3.npm uninstall react-native 4.npm i xx@指定版本
- ssh_key认证
ssh认证流程步骤: 1.主机host_key认证 2.身份验证 3.身份验证通过 原理及更多知识点,请查看好友博客 http://www.cnblogs.com/f-ck-need-u/p/7129 ...
- pymongo(看后转载,在原基础上添加了类连接和简单调用)
一.MongoDB 数据库操作 1. 连接数据库 import pymongo conn = pymongo.Connection() # 连接本机数据库 # conn = pymongo.Conne ...