第一题
牛棚的安排
(File IO): input:reserve.in output:reserve.out
Time Limits: 1000 ms Memory Limits: 65536 KB Detailed Limits
Goto ProblemSet
Description
FJ的N(1<=N<=50,000)头奶牛实在是太难伺候了,她们甚至有自己独特的产奶时段。当然对于某一头奶牛,她每天的产奶时段是固定的,为时间段A..B(1<=A<=B<=1,000,000),包括时间段A和时间段B。显然,FJ必须开发一个调控系统来决定每头奶牛应该被安排到哪个牛棚去挤奶,因为奶牛们显然不希望在挤奶时被其它奶牛看见。
FJ希望你帮他计算一下:
如果要满足奶牛们的要求,并且每天每头奶牛都要被挤过奶,至少需要多少牛棚
Input
第1行: 一个单独的整数N,为奶牛的总数
第2..N+1行: 每行包括2个用空格隔开的正整数,第i+1行的数据描述的是第i头奶牛的产奶时段
Output
第1行: 输出一个整数M,表示最少需要的牛棚数
Sample Input
5
1 10
2 4
3 6
5 8
4 7
Sample Output
4
Data Constraint
Hint
【样例说明】
以下是一张与本题输出对应的奶牛产奶时刻表:
时间段 1 2 3 4 5 6 7 8 9 10
牛棚 1 c1>>>>>>>>>>>>>>>>>>>>>>>>>>>
牛棚 2 .. c2>>>>>> c4>>>>>>>>> .. ..
牛棚 3 .. .. c3>>>>>>>>> .. .. .. ..
牛棚 4 .. .. .. c5>>>>>>>>> .. .. ..
(ci表示第i头奶牛)
其他需要同样数目的牛棚的合法输出也是正确的。
题解:嗯,先按开始时间排个序,然后暴力扫很多遍,开个O2开关,就特么过啦。
原谅我不会其他解法,毕竟我太弱啦…………
#pragma GCC optimize("O2")
#pragma G++ optimize("O2")
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,num=0,ans=0,l,r,w;
struct hh
{
int l,r;
}a[50001];
bool come(hh a,hh b)
{
if(a.l!=b.l)
return a.l<b.l;
else return a.r<b.r;
}
int main()
{
freopen("reserve.in","r",stdin);
freopen("reserve.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].l,&a[i].r);
}
sort(a+1,a+1+n,come);
while(num<n)
{
for(int i=w+1;i<=n;i++)
{
if(a[i].l!=-1)
{
w=i;
l=a[w].l;
r=a[w].r;
a[w].l=-1;
a[w].r=-1;
num++;
break;
}
}
ans++;
for(int i=w+1;i<=n;i++)
{
if(a[i].l>r)
{
num++;
l=a[i].l;
r=a[i].r;
a[i].l=-1;
a[i].r=-1;
}
}
if(num==n)
break;
}
cout<<ans;
fclose(stdin);
fclose(stdout);
return 0;
}
第二题
数字游戏
(File IO): input:easy.in output:easy.out
Time Limits: 1000 ms Memory Limits: 65536 KB Detailed Limits
Goto ProblemSet
Description
Charles和sunny在玩一个简单的游戏。若给出1~n的一个排列A,则将A1、A2相加,A2、A3相加……An-1、An相加,则得到一组n-1个元素的数列B;再将B1、B2相加,B2、B3相加,Bn-2、Bn-1相加,则得到一组n-2个元素的数列……如此往复,最终会得出一个数T。而Charles和sunny玩的游戏便是,Charles给出n和T,sunny在尽可能短的时间内,找到能通过上述操作得到T且字典序最小的1~n的排列。(sunny大声说:“What an easy game!”,接着几下就给出了解),Charles觉得没意思,就想和你玩,当然,你可以用一种叫做“电子计算机”的东西帮你。
Input
本题有多组数据,对于每组数据:一行两个整数n(0< n<=20),t即最后求出来的数。两个0表示输入结束。
Output
对于每组测试数据输出一行n个整数,用空格分开,行尾无多余空格,表示求出来的满足要求的1~n的一个排列。
Sample Input
4 16
3 9
0 0
Sample Output
3 1 2 4
1 3 2
Data Constraint
Hint
【样例说明】
开始排列: 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。
题解:dfs搜索,注意剪枝,剪得好AC,剪不好就40,那怎么剪呢?
剪枝一:加一个小小的优化,就是在确定第X个数时,保证新求出来的sum不能大于T,加上这个优化后,可以得40分;
剪枝二:由于C(N-1,i)=C(N-1,N-1-i),具有对称性,题目又要求最小字典序列,所以在枚举时当j>n /2 时,要保证a[j]>a[N+1-j],这样程序速度会提高,但是该题还是只能得40分;
剪枝三:当枚举到第i个数时,剩余的N-i个数,与剩余的N-i个系数一一对应,让大数和大系数相乘,小数和小系数相乘可以得到最大值,让大数和小系数相乘,小数和大系数相乘可以得到最小值,如果剩余的值不在这个范围内,就不要搜下去,这样可以大大优化;
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,t,ans=0,a[100000],r=0;
int jz[10000],jzz=0,maxx,minn;
bool h[100000];
long long int xs[100000],jc[25],xs2[10000];
void dfs(int i,int sum)
{
jzz=0;
maxx=0;
minn=0;
int jj=i;
int xx=0;
for(int j=1;j<=n;j++)
{
if(h[j]==false)
{
jzz++;
jz[jzz]=j;
xx++;
xs2[xx]=xs[jj];
jj++;
}
}
sort(jz+1,jz+1+jzz);
sort(xs2+1,xs2+xx+1);
int num=n;
for(int j=1;j<=n-i+1;j++)
{
maxx+=xs2[j]*jz[j];
minn+=xs2[j]*jz[jzz-j+1];
}
int tt=t-sum;
if(maxx<tt||minn>tt)//剪枝三
return ;
if((i-1)>n/2)
if(a[i-1]<a[2+n-i])//剪枝二
return ;
if(sum>t) return ;//剪枝一
if(r==100) return ;
int j;
for(int j=1;j<=n;j++)
{
if(r==100) return ;
if(h[j]==false)
{
h[j]=true;
a[i]=j;
if(i<n)
{
dfs(i+1,sum+(j*xs[i]));
}
else if(i==n)
{
if(sum+j==t)
{
r=100;
for(int i=1;i<=n;i++)
{
cout<<a[i]<<" ";
}
cout<<endl;
return;
}
}
h[j]=false;
}
}
}
void hhh()
{
xs[1]=1;xs[n]=1;
for(int i=2;i<n;i++)
{
xs[i]=jc[n-1]/(jc[i-1]*jc[n-i]);
}
}
int main()
{
freopen("easy.in","r",stdin);
freopen("easy.out","w",stdout);
jc[1]=1;
for(int i=2;i<=21;i++)
{
jc[i]=jc[i-1]*i;
}
while(1)
{
memset(h,false,sizeof(h));
memset(a,0,sizeof(a));
scanf("%d%d",&n,&t);
if(n==0&t==0) break;
hhh();
r=0;
dfs(1,0);
}
return 0;
}
第三题
- 为奶牛熄灯
(File IO): input:xlite.in output:xlite.out
Time Limits: 1000 ms Memory Limits: 65536 KB Detailed Limits
Goto ProblemSet
Description
奶牛们喜欢在黑暗的环境里睡觉。当她们每晚回到牛棚准备睡觉时,牛棚里有L(3<=L<=50)盏灯仍然亮着。所有灯的开关按编号升序排成一列,最左边的那个开关控制1号灯(所谓控制,也就是如果1号灯现在亮着,那么按这个开关会使1号灯熄灭,否则这个操作会使1号灯被点亮)。由于奶牛们的蹄子过于粗大,没法方便地按开关,她们总是用一个特制的干草叉来进行对开关的操作。这个叉子设计了T(1<=T<=7)个叉尖,相邻叉尖的距离正好与相邻开关的距离相等。但是现在有些叉尖被折断了。比如说,T=4的一个干草叉,它的第3根叉尖被折断了,我们就用’1101’来描述它。
如果把这个叉子的最左端对准那一列开关的最左端,按下,那1号、2号和4号灯的状态会被改变(3号灯的状态不变,因为那个叉尖被折断了)。在进行这样的操作的时候,任何一个叉尖都必须有一个对应的开关,也就是说,叉子的边缘不能在那一列开关的范围外,即使边缘处的叉尖已经被折断。
现在,你已经知道了各个灯的状态,以及干草叉现在的情况,请你找出一个操作序列,使得在所有操作完成之后,仍然亮着的灯的数目最少。
Input
第1行: 两个用空格隔开的整数:L 和 T
第2行: 一个长度为L的字符串,串中不含空格且元素均为’0’或’1’。第i个元素是’1’则表示第i盏灯亮着,是’0’的话就表示第i盏灯已经被关掉
第3行: 一个长度为T的字符串,只含’0’或’1’(同样不含空格)。如果第i个元素是’1’,说明干草叉的第i根叉尖仍完好无损,否则说明第i根叉尖已经被折断
Output
第1行: 输出一个正整数K,即为了达到目的一共需要用叉子按多少次开关
Sample Input
10 4
1111111111
1101
Sample Output
5
Data Constraint
Hint
【样例说明】
所有的10盏灯都开着。奶牛们使用的干草叉有4个齿,其中第3个齿已经被折断了。
1111111111 开始
1100101111 操作 3(即为把叉子的第一个齿对准第3个开关,按下)
0001101111 操作 1
0000000111 操作 4
0000001010 操作 7
0000010000 操作 6
最后,有1盏灯仍然亮着。这是借助这个干草叉所能得到的最佳结果。当然,可行操作还有很多(最后剩下的灯可能不同)。
第四题
题目:巴比伦