A. Paper Airplanes
简单数学模拟题。
#include
using namespace std;
typedef long long ll;
ll k,n,s,p;
int main(){
scanf("%I64d%I64d%I64d%I64d",&k,&n,&s,&p);
ll each=ceil(1.0*n/s);
ll tot=each*k;
ll ans=1ll*ceil(1.0*tot/p);
cout<return 0;
}
B. Battleship
在一个 n∗n n ∗ n 的网格图中,一些点具有障碍。可在空矿的地方放置一艘船,船长 k k 即需要有连续k个空位。
求被最多方案覆盖的方格。
n,k<=100 n , k <= 100
一艘船覆盖的地方显然都是空格,这些格子答案都加 1 1 。
然后我们可以把障碍和空格分别看成1 0 求前缀和即可快速获得这个地方能不能放船。
问题就变成了多次区间加,最后查询最大值。差分即可。
#include
using namespace std;
const int MAXN=105;
int mmap[MAXN][MAXN],sum[MAXN][MAXN],cf[MAXN][MAXN],ans[MAXN][MAXN],ans2[MAXN][MAXN],h=1,l=1,ansp=0,n,k;
char s[MAXN];
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%s",s);
for(int j=0;jif(s[j]=='#')mmap[i][j+1]=1;
else mmap[i][j+1]=0;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
sum[i][j]=sum[i][j-1]+mmap[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(j+k-1>n)break;
if(sum[i][j-1]==sum[i][j+k-1])cf[i][j]++,cf[i][j+k]--;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
ans[i][j]=ans[i][j-1]+cf[i][j];
}
}
memset(sum,0,sizeof(sum));
memset(cf,0,sizeof(cf));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
sum[j][i]=sum[j-1][i]+mmap[j][i];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(j+k-1>n)break;
if(sum[j-1][i]==sum[j+k-1][i])cf[j][i]++,cf[j+k][i]--;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
ans2[j][i]=ans2[j-1][i]+cf[j][i];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(ans[i][j]+ans2[i][j]>ansp){
ansp=ans[i][j]+ans2[i][j],h=i,l=j;
}
}
}
cout<" "<return 0;
}
C. Greedy Arkady
k k 个小朋友围成一圈分 n n 个糖 按照 1−k−1 1 − k − 1 的顺序轮流给糖。每次给 x x 块糖 不足 x x 块糖则丢掉结束。
规定 x<=M x <= M 且 没有小朋友分到的糖的次数比D多(圈数)。求 1 1 号小朋友最多分到多少颗糖。
(2≤n≤1018,2≤k≤n,1≤M≤n,1≤D≤min(n,1000),M⋅D⋅k≥n) ( 2 ≤ n ≤ 10 18 , 2 ≤ k ≤ n , 1 ≤ M ≤ n , 1 ≤ D ≤ m i n ( n , 1000 ) , M ⋅ D ⋅ k ≥ n )
发现D非常小。
如果D已知,我们可以贪心求出 1 1 号小朋友的糖数。就是 1 1 号小朋友拿 D D 次糖,其他人拿 D−1 D − 1 次糖。
得到 Dx+(D−1)(k−1)x<=n D x + ( D − 1 ) ( k − 1 ) x <= n
Dkx−kx+x<=n D k x − k x + x <= n
x(Dk−k+1)<=n x ( D k − k + 1 ) <= n
x<=n/(Dk−k+1) x <= n / ( D k − k + 1 )
当 x x 取 n/(Dk−k+1) n / ( D k − k + 1 ) 时最优。枚举每个 D D 求答案。
注意特判 x==m x == m 。
若 x==0 x == 0 结束输出答案
#include
using namespace std;
typedef long long ll;
ll n,k,m,d,ans=0;
inline ll read(){
char c=getchar();ll x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
//(i-1)kx + x <= n
//kix -kx +x<=n
//(ki-k+1)x<=n
//n/(ki-k+1)=x
//n/(k(i-1)+1)=x
int main(){
n=read();k=read();m=read();d=read();
ans=ceil((n/m)/(1.0*k))*m;
for(int i=1;i<=d;i++){
ll x=n/(k*(i-1)+1);
if(x==0)break;
if(x>m)continue;
ans=max(ans,1ll*i*x);
}
cout<return 0;
}
/*
*/
D. Single-use Stones
有一些青蛙过河。河宽 w w . 他们每次可以跳 [1,l] [ 1 , l ] 区间内任意长度。河上每个位置 i i 有 ai a i 个 石头,踩一下就会沉下去。最大化青蛙过河的只数。
w<=105ai<=104 w <= 10 5 a i <= 10 4
在河岸的青蛙会跳满目前所能跳到的所有石头。即使他们最终无法到达河对岸。这显然是最优的。
对于位置 i i 上的青蛙 他可以跳到 区间内有石头的任意位置,但显然最右边的石头是最优的。
我们发现 从 i i 到 i+1 i + 1 的青蛙,他们所能跳到的区域之相差左右两端。有 l−2 l − 2 个是重复的。
所以这个东西。。我们可以直接 开 deque d e q u e 贪心模拟 线性复杂度。每个点最多进队一次出队一次。
#include
using namespace std;
const int MAXN=1e5+5;
int a[MAXN],csd[MAXN],ans=0,w,l;
struct data{
int pos,remain;
};
dequeq;
int main(){
scanf("%d%d",&w,&l);
for(int i=1;iscanf("%d",&a[i]);
}
for(int i=1;i<=l;i++){
csd[i]=a[i];
}
for(int i=1;i<=w;i++){
int to=i+l;
while(q.size()&&i>=q.front().pos)q.pop_front();
if(toif(csd[i]){
if(i+l>=w){ans+=csd[i];continue;}
while(q.size()&&csd[i]){
if(csd[i]>=q.back().remain){
csd[i]-=q.back().remain;//
csd[q.back().pos]+=q.back().remain;
q.pop_back();
}
else{
int v=q.back().pos,num=q.back().remain-csd[i];
csd[v]+=csd[i];
csd[i]=0;
q.pop_back();
q.push_back((data){v,num});
}
}
}
}
cout<return 0;
}
// front -> back
// X 0 4 1 3 1
E - Short Code
有 n n 个单词,我们可以把每个单词用他的某个前缀来表示。但要求不能有任意两个单词表示方法相同。最小化这些前缀长度和。
n<=105 n <= 10 5
∑len<=105 ∑ l e n <= 10 5
前缀问题很容易想到 trie t r i e 树,我们把单词建 trie t r i e 树发现问题转化为。对于每个 val==1 v a l == 1 的节点,找到一个祖先与之匹配,最小化祖先深度和。显然有一个贪心就是尽量把树的上面放满。我们思考对于一个所有子树已经最优的情况 根是空着的。我们显然要把子树中关键点最深的提到根。这样达到最优。如果根也有值,那么这个子树直接就是最优的。
所以这个东西转化成了按照从叶子向根的顺序 单点修改子树查询。线段树可以解决。
但是 由于这个问题是在树中的qwq, 可以记录 最大值 次大值来 DP D P ? 或许? 瞎口胡的qwq。
#include
using namespace std;
const int MAXN=1e5+10;
int c[MAXN][26],cnt=1,size[MAXN],fa[MAXN],top[MAXN],dep[MAXN],hson[MAXN],val[MAXN];
void insert(char *s){
int len=strlen(s),now=1;
for(int i=0;iint v=s[i]-'a';
if(!c[now][v])c[now][v]=++cnt;
now=c[now][v];
}
val[now]++;
}
void dfs1(int u,int father){
dep[u]=dep[father]+1;
fa[u]=father;
size[u]=1;
for(int i=0;i<26;i++){
if(c[u][i]){
int v=c[u][i];
dfs1(v,u);
size[u]+=size[v];
if(!hson[u]||size[hson[u]]int rl[MAXN],rk[MAXN],tim=0;
void dfs2(int u,int tp){
rk[u]=++tim;
rl[tim]=u;
top[u]=tp;
if(hson[u])dfs2(hson[u],tp);
for(int i=0;i<26;i++){
if(c[u][i]){
int v=c[u][i];
if(v==hson[u])continue;
dfs2(v,v);
}
}
}
typedef pair<int,int>par;
#define mp make_pair
struct xds{
#define lson (o<<1)
#define rson (o<<1|1)
int maxdep[MAXN<<2],post[MAXN<<2],sumv[MAXN<<2];//pos 真实的节点
void pushup(int o){
maxdep[o]=0,post[o]=-1;
if(maxdep[lson]>maxdep[o])maxdep[o]=maxdep[lson],post[o]=post[lson];
if(maxdep[rson]>maxdep[o])maxdep[o]=maxdep[rson],post[o]=post[rson];
sumv[o]=sumv[lson]+sumv[rson];
}
void build(int o,int l,int r){
if(l==r){
if(val[rl[l]]){
sumv[o]=maxdep[o]=dep[rl[l]];
post[o]=rl[l];
}
else sumv[o]=maxdep[o]=0,post[o]=-1;
return;
}
int mid=l+r>>1;
build(lson,l,mid);build(rson,mid+1,r);
pushup(o);
}
void change(int o,int l,int r,int pos,int ty){//填id
if(l==r){
if(ty){
sumv[o]=maxdep[o]=dep[rl[l]];
post[o]=rl[l];
}
else sumv[o]=maxdep[o]=0,post[o]=-1;
return ;
}
int mid=l+r>>1;
if(pos<=mid)change(lson,l,mid,pos,ty);
else change(rson,mid+1,r,pos,ty);
pushup(o);
}
par query(int o,int l,int r,int ql,int qr){
if(ql<=l&&qr>=r) return mp(maxdep[o],post[o]);
int mid=l+r>>1;par t1=mp(0,-1),t2=mp(0,-1);
if(ql<=mid)t1=query(lson,l,mid,ql,qr);
if(qr>mid)t2=query(rson,mid+1,r,ql,qr);
if(t1.first>t2.first)return t1;
return t2;
}
}T;
void getans(int u){
for(int i=0;i<26;i++){
if(c[u][i]){
getans(c[u][i]);
}
}
if(!val[u]){
par tem=T.query(1,1,cnt,rk[u],rk[u]+size[u]-1);
if(tem.first){
T.change(1,1,cnt,rk[tem.second],0);
T.change(1,1,cnt,rk[u],1);
}
}
}
int n;
char qwq[MAXN];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",qwq);
insert(qwq);
}
dep[0]=-1;
val[1]=1;
dfs1(1,0);
dfs2(1,0);
T.build(1,1,cnt);
//cout<
getans(1);
cout<1 ]<return 0;
}
/*
null
c
o
d
e
f h
o o
r r
c c
e e
1s 1s
null
a
1a 1b
c 1b
a 1a
d
1a
0
0 1
2 3 1
1 2 1
1 1
1
*/