这次比赛200分,第5,比赛最后最后2分半时切掉T3,不错……
“有了金坷垃,肥料一袋能顶两袋撒,小麦亩产一千八,吸收两米下的氮磷钾……”,话说HYSBZ(Hengyang School for Boys & Zy)学识渊博孩纸们一讲到粮食,都会想起印度那个著名的故事:国王要在第一个格子里放入一粒小麦,接下来的格子放入前面一个格子的两倍的小麦。这样所需小麦总数是巨大的,哪是不用金坷垃就能完成的任务?不过为了减轻国王的任务,那个下棋获胜的宰相换了一个要求:“我只需要你在棋盘外放一粒小麦,可以将其理解为第0 个格子,然后你需要在第一个格子里放入p粒小麦,之后每一个格子放入前两个格子的小麦数之和的小麦,并且要满足第a 个格子放x 粒小麦,第b 个格子放……”说到这,宰相突然发现自己说的满足第a 个格子放x 粒小麦的情况可能不存在……欺君可是大罪啊!国王看到宰相迟迟不说,自己也烦了!我自己来算!于是国王拜托你,让你算出第b 个格子应该放几粒小麦。当然,就算答案不存在,你也是要告诉国王的。
该题有多组数据,请读到文件末结束。
对于每一组数据仅一行,3 个正整数a,x,b,分别表示第a 个格子放了x 粒小麦,以及你所需要计算的是第b 个格子的小麦数量。
对于每一次询问,仅1 个整数,为第b 个格子的小麦数量,若宰相说的情况不存在,那么请输出-1。
1 1 2
3 5 4
3 4 6
12 17801 19
2
8
-1
516847
对于样例二,f[1]=2 时,能够满足f[3]=5,因此宰相没有撒谎,此时第5 个格子的小麦数应为f[4]=f[2]+f[3]=3+5=8.
对于50%的数据:如果答案存在,那么p<=50
对于100%的数据:1<=数据组数<=10000,1<=a,b<=20, 数据保证如果答案存在,那么1<=p<=1000000.
比赛&正解思路: 找规律,题目有点像斐波那契数列,手摸一下就能发现规律……
反思: 日常签到题,淼
#include
using namespace std;
long long a,x,b,f[25];
int main()
{
long long i;
f[0]=1;
f[1]=1;
for (i=2;i<=20;i++)
f[i]=f[i-1]+f[i-2];
while (~scanf("%lld%lld%lld",&a,&x,&b))
{
if (a==1)
{
long long l,r,k;
l=1;
r=x;
k=x;
for (i=2;i<=b;i++)
{
k=l+r;
l=r;
r=k;
}
printf("%lld\n",k);
continue;
}
long long t;
t=x-f[a];
if (t%f[a-1]==0)
{
long long l,r,k;
l=1;
r=1+t/f[a-1];
for (i=2;i<=b;i++)
{
k=l+r;
l=r;
r=k;
}
printf("%lld\n",k);
}
else printf("-1\n");
}
return 0;
}
“蓝猫淘气三千问,看蓝猫,我有姿势我自豪!”话说能考上HYSBZ的孩纸们肯定都是很有姿势的孩纸们,但是大家普遍偏科,都只有一门科目考得好。已知HYSBZ的入学考试科目数量小于等于10^9,而有n个学生参加了入学考试。现在HYSBZ要刷人了,招生办每一次刷人会把一个科目考得好的人全部刷掉,但是最多不能刷超过K次。(刷就是不录取)而HYSBZ的校长看录取名单时,最喜欢看的就是连续都是同一个科目考得好的人。他定义完美学生序列为连续且考得好的科目都为同一门的学生序列。现在招生办主任想让你帮他设计一种录取方案,使得最长的完美学生连续子序列尽量长。
共N+1行,第一行2个正整数n,K,n表示入学考试人数,K表示刷人次数上限。
接下来N行,每行仅一个正整数Ai,为i号学生所考得好的科目。
仅1个正整数,为最长的最长完美学生连续子序列。
9 1
2
7
3
7
7
3
7
5
7
4
总共有9个学生,最多只能刷一次学生。
若不刷,最长完美学生连续子序列长度为2
若刷掉考第3门考得好的学生,则学生序列变成2 7 7 7 7 5 7,最长完美学生连续子序列长度为4.
对于10%的数据:n<=10
对于30%的数据:n<=1000
对于100%的数据:1<=n<=100000
比赛思路: 离散化加DP(乱搞一通)
正解思路: 队列处理区间(其实看了题解之后觉得特水),还可以用hash或者离散化 (本蒟蒻太菜,还没码)
反思: 考试的思路不能太局限,不然简单的题目容易想难了
#include
using namespace std;
int n,k,ans;
queue<int>d;
map<int,int>sum;
int main()
{
scanf("%d%d",&n,&k);
int i,x,tot;
tot=0;
for (i=1;i<=n;i++)
{
scanf("%d",&x);
if (!sum[x])
{
tot++;
while (tot>k+1)
{
int t=d.front();
sum[t]--;
if (!sum[t]) tot--;
d.pop();
}
}
sum[x]++;
d.push(x);
if (sum[x]>ans) ans=sum[x];
}
printf("%d\n",ans);
return 0;
}
休息的时候,可以放松放松浑身的肌肉,打扫打扫卫生,感觉很舒服。在某一天,某LMZ 开始整理他那书架。已知他的书有n 本,从左到右按顺序排列。他想把书从矮到高排好序,而每一本书都有一个独一无二的高度Hi。他排序的方法是:每一次将所有的书划分为尽量少的连续部分,使得每一部分的书的高度都是单调下降,然后将其中所有不少于2 本书的区间全部翻转。重复执行以上操作,最后使得书的高度全部单调上升。可是毕竟是休息时间,LMZ 不想花太多时间在给书排序这种事上面。因此他划分并翻转完第一次书之后,他想计算,他一共执行了多少次翻转操作才能把所有的书排好序。LMZ 惊奇地发现,第一次排序之前,他第一次划分出来的所有区间的长度都是偶数。
第一行一个正整数n, 为书的总数。
接下来一行n个数,第i个正整数Hi,为第i 本书的高度。
仅一个整数,为LMZ 需要做的翻转操作的次数。
6
5 3 2 1 6 4
3
第一次划分之后,翻转(5,3,2,1),(6,4)。之后,书的高度为1 2 3 5 4 6,然后便是翻转(5,4)即可。
对于10%的数据:n<=50
对于40%的数据:n<=3000
对于100%的数据:1<=n<=100000, 1<=Hi<=n
比赛&正解思路: 先把所有的降序子序列全部翻转,之后求一下逆序对,结果相加就行 (结论我是手摸出来的)
下面给出官方解释:
在找出所有的单调下降序列并翻转后,可以发现,刚刚找到的区间内的元素都已经变得有序。
也就是说,只有两个小区间之间的数可以进行交换。
显然,我们只会交换两个降序的数。即逆序对。
因此答案为逆序对数与翻转次数之和。
反思: 要多从其他角度切入问题
#include
using namespace std;
int a[100005],b[100005],n,c[100005];
long long ans;
void gb(int i,int j)
{
int l,r,mid,k;
if (i==j) return;
mid=(i+j)>>1;
gb(i,mid);
gb(mid+1,j);
l=i;
r=mid+1;
k=i;
while (l<=mid && r<=j)
{
if (a[l]<=a[r])
{
b[k]=a[l];
l++;
k++;
}
else
{
ans+=mid-l+1;
b[k]=a[r];
r++;
k++;
}
}
while (l<=mid)
{
b[k]=a[l];
l++;
k++;
}
while (r<=j)
{
b[k]=a[r];
r++;
k++;
}
for (k=i;k<=j;k++)
a[k]=b[k];
}
int main()
{
scanf("%d",&n);
int i;
for (i=1;i<=n;i++)
{
scanf("%d",&a[i]);
c[i]=a[i];
}
a[n+1]=0x3f3f3f3f;
int l;
l=1;
ans=0;
for (i=1;i<=n;i++)
{
if (a[i]<a[i+1])
{
int j;
for (j=l;j<=i;j++)
a[j]=c[i-j+l];
l=i+1;
ans++;
}
}
gb(1,n);
printf("%lld\n",ans);
return 0;
}