在游戏中,你将得到一个长度为
n
的序列
a
1
...a
n
和一个棋子,一开始棋子放在
a
1
处,你的得分为
a
1
。接下来你可以做出
n
次选择,以使自己的得分最大化。
第
i
次选择,你可以决定是否使棋子前进
2
i
−
1
的距离。若前进,则你的得分加上移动后位置上的数
字;若不前进,则什么也不会发生。
特别地,如果走到了序列外面(前进的距离大于等于
n
),将把已经获得的分数清零,即总分
0
分。
请你做出最恰当的选择,并输出最高可能的得分
由于每个数的二进制分解是唯一的,所以走到一个点的方法是唯一的,所以可以枚举所有点,计算出终点为此点时的得分,比较得到所有得分中最大的就是答案
const long long N=1000005;
long long n,aa,ans,xi=0;
long long a[N],g[N];
int m;
int zh(int b) // 写了一个函数,把点的下标转成二进制数求他的位数
{
int i=0;
while(b!=0)
{
++i;
b/=2;
}
return i;
}
long long j(int b) // 再写一个函数算该店的得分,某点的得分等于该点下标减去他的二进制最高位再加上该店的数
{
//cout<<b<<endl;
if(b==0) return ans=a[0];
else{
ans=g[(b-(1<<(m-1)))]+a[b]; //
return ans;
}
}
int main()
{
scanf("%lld",&n);
for(int i=0;i<n;i++)
{
scanf("%lld",&aa);
a[i]=aa;
}
for(int i=0;i<n;i++)
{
m=zh(i); // m是二进制最高位
// printf("%d\n",m);
g[i]=j(i);
// cout<<i<<' '<<g[i];
if(xi<g[i]) xi=g[i];
}
if(xi>0) printf("%lld",xi);
else printf("0");
return 0;
}
小
f
想在一张格子纸上写一段话。可是小
f
不知道还能不能写的下。
这张长方形纸有
n
行
m
列,其中有一些行和一些列已被涂黑,而其余地方是干净的。
小
f
想要写的话一共包含
k
个字,他希望每个格子里写一个字;不能写在涂黑的格子里,也不能被
涂黑的格子分割成几部分。
请问这张纸还能写下小
f
的话吗?
第一行一个数字
T
表示测试组数
接下来输入
T
组测试数据,每一组测试数据形如:
第一行四个整数
n, m, p, q, w
,表示总行数、总列数、涂黑的行数、涂黑的列数,小
f
想要写下的字数
第二行从小到大
p
个整数,表示写满字的行的编号
第三行从小到大
q
个整数,表示写满字的列的编号
因为是整行涂黑,所以所有空白部分都是矩形,所以最大空白行距乘以最大空白列距就是最大空位,这样就可以开两个数组,将行和列分别计算再相乘,不用开二维数组,会爆内存。
const long long N=1000005;
int t,n,m,p,q,x,y;
long long w,da1=-3,da2=-3; // 注意数据范围是1e6,所以w最大是1e6*1e6,要开long long
int h[N],l[N];
int zdh,zdl;
int main()
{
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
zdh=0;zdl=0;da1=-3;da2=-3;
memset(h,0,sizeof(h));
memset(l,0,sizeof(l)); // 总共有t组数据,所以每次数组要清零
scanf("%d%d%d%d%lld",&n,&m,&x,&y,&w);
for(int j=1;j<=x;j++)
{
scanf("%d",&p);
h[p]=1; // 被涂黑的就标记成1
}
for(int j=1;j<=y;j++)
{
scanf("%d",&q);
l[q]=1;
}
for(int j=1;j<=n;)
{
while(h[j]==0&&j<=n) // 如果是0,就是空白处,就一直++直到不是0
{
zdh++;
j++;
}
j++; //while外面也要++,不然会死循环
if(da1<zdh) da1=zdh;zdh=0; // 找出最大的空白行距,然后把这次计算的行距归零
}
for(int j=1;j<=m;)
{
while(l[j]==0&&j<=m)
{
zdl++;
j++;
}
j++;
if(da2<zdl) da2=zdl;zdl=0;
}
//printf("%d %d %d\n",da1,da2,da1*da2);
if(da1*da2>=w) printf("Y\n");
else printf("N\n");
}
return 0;
}
世界可视为
N
∗
N
个城市排列成的方阵,其中有
M
个重要城市。小
c
想在某一个重要城市
F
中引
爆鲜花炸弹,这会让以
F
为中心,边长为
d
的正方形所覆盖的所有城市开满鲜花。
经过粗略计算,小
c
发现想让所有城市开满鲜花所需的成本过于巨大,于是他觉得只要所有重要城
市都开满鲜花就可以了。
然而,小
c
发现即使只让重要城市开满鲜花也是很困难的一件事,这次他觉得有至少一半的重要城
市能够开花就足够了。
小
c
想知道需要制作多大的炸弹,但他算不出来。请你告诉他想要达成目标所需的最小的
d
。
请将城市视为方格而非两条线的交点。边长为
1
的正方形只覆盖这个城市本身,边长为
3
的正方形
将覆盖以引爆点为中心的
3
×
3
个城市。
这个正方形可以超出世界边界,超出部分不产生影响。
Input
第一行两个数字
n, m
接下来
m
行,每行两个数字
x, y
表示在第
x
行第
y
列坐落着一个重要城市,坐标范围均为
1
到
n
Output
一个数字表示所需的最小的正方形的边长
.
由于正方形的中心必定位于一个城市,它的边长一定是个 奇数
const int N=1505;
int n,d,x,y,ans,p,q,da=10000;
int xx[N],yy[N];
double m,mm;
long long z[N][N]; // 数组不能太大,不然就爆内存了
int f(int a,int b)
{
ans=0;
p=a-d/2;
q=b-d/2;
for(int i=1;i<=m;i++)
{
if(xx[i]>=p&&xx[i]<=p+d-1&&yy[i]>=q&&yy[i]<=q+d-1) ans++; // 扫过所有重要城市,看是否在爆炸范围内,如果在就加一
}
return ans;
}
int main()
{
scanf("%d%lf",&n,&m);
mm=ceil(m/2); // 至少覆盖一半重要城市,向上取整,注意开double
memset(z,0,sizeof(z));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
z[i][j]=0;
}
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
xx[i]=x; // 开两个数组把横纵坐标存起来
yy[i]=y;
z[x][y]=1; // 有重要城市的点设成1
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
d=1; // 注意每次初始化边长为1
if(z[i][j]==1)
{
while(f(i,j)<mm) // 以重要城市为中心,边长为1开始,看能否覆盖到足量城市,不能就把边长加2
{
d+=2;
f(i,j);
}
if(f(i,j)>=mm)
{
if(da>d) da=d; // 记录下最小的能达到要求的边长
}
}
}
}
printf("%d\n",da);
return 0;
}
小
q
是个时空管理员,他有一台监视时间的设备。这台设备上有
12
个表盘,第
i
个表盘上有
i
个刻
度,分别标有
0
,
1
,
2
...i
−
1
,经过一秒时间,所有表盘的指针都会移动恰好一个刻度。小
q
就是用这样一
台机器监视着时间流动的。
在某个时间,小
q
把所有表盘都复位到了
0
.
过了不知道多少时间,他又看了一眼表盘,并记住了那
一瞬间
12
个表盘的示数。小
q
想确认已经过去了多久,请你告诉他,以秒为单位。如果有多种可能性,
输出数值最小的一种,可以为
0
。
如果表盘的示数情况不可能存在,说明小
q
要被炒鱿鱼了,请输出
”gg”
。
思路比较重要,代码很好写,正确做法是直接枚举答案,然后逐个检查是否符合
ans
≡
a
i
mod
i
即可。
#include<bits/stdc++.h>
using namespace std;
int tt,ans,da=1000009;
int t[13],shu[13];
bool tf;
int main()
{
for(int i=1;i<=12;i++)
{
scanf("%d",&tt);
t[i]=tt; // t数组是输入的表盘示数
}
for(int i=0;i<=1000000;i++) // 从零开始枚举时间,一直到最大时间限制
{
tf=true; // 初始是true
for(int j=1;j<=12;j++)
{
shu[j]=i%j; // shu数组是当前时间下表盘的示数
if(shu[j]!=t[j]) tf=false; // 有一个表盘不符合就是false
}
if(tf==true&&da>i) da=i; // 记录下最小时间
}
if(da!=1000009) printf("%d",da);
else printf("gg"); // 如果没有符合的就输出gg
return 0;
}
using namespace std;
int tt,ans,da=1000009;
int t[13],shu[13];
bool tf;
int main()
{
for(int i=1;i<=12;i++)
{
scanf("%d",&tt);
t[i]=tt; // t数组是输入的表盘示数
}
for(int i=0;i<=1000000;i++) // 从零开始枚举时间,一直到最大时间限制
{
tf=true; // 初始是true
for(int j=1;j<=12;j++)
{
shu[j]=i%j; // shu数组是当前时间下表盘的示数
if(shu[j]!=t[j]) tf=false; // 有一个表盘不符合就是false
}
if(tf==true&&da>i) da=i; // 记录下最小时间
}
if(da!=1000009) printf("%d",da);
else printf("gg"); // 如果没有符合的就输出gg
return 0;
}