原题地址
回归
,这场堪堪上紫。
A.Petya and Origami
【题目大意】
一本笔记本有
页,每个笔记本只能染成红绿蓝其中一种颜色,需要
页红色,
页绿色,
张蓝色,问最少需要多少本笔记本。
【解题思路】
颜色不相关,分开计算即可。
【参考代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k,ans;
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
#endif
n=read();k=read();
ans=(ll)(n*2-1)/k+1+(ll)(n*5-1)/k+1+(ll)(n*8-1)/k+1;
printf("%lld\n",ans);
return 0;
}
B.Margarite and the best present
【题目大意】
数列
,
求
,
【解题思路】
差分求前缀和,每两个元素看成一组计算即可。
【参考代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll q,l,r,ans;
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
ll calc(ll x)
{
if(x%2==0) return x/2;
return x/2-x;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
#endif
q=read();
while(q--)
{
ll l=read(),r=read();
ans=calc(r)-calc(l-1);
printf("%lld\n",ans);
}
return 0;
}
C.Masha and two friends
【题目大意】
一个
的国际象棋棋盘,左下角为白格,接下来将棋盘的一个矩形所有格染白,再将另一个矩形所有格染黑,问白格和黑格各有多少个,多组数据。
【解题思路】
计算出每个矩形对应原始棋盘的多少个黑格及白格,容斥计算即可。
【参考代码】
#include<bits/stdc++.h>
#define mkp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pii;
ll n,m;
pii ans;
ll read()
{
ll ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
struct point{ll x,y;};
struct node
{
point a,b;
node(){}
node(ll x,ll y,ll xx,ll yy){a.x=x;a.y=y;b.x=xx;b.y=yy;}
void init(){a.x=read();a.y=read();b.x=read();b.y=read();}
}p1,p2,emp;
pii operator -(const pii&x,const pii &y){return mkp(x.fi-y.fi,x.se-y.se);}
pii operator +(const pii&x,const pii &y){return mkp(x.fi+y.fi,x.se+y.se);}
pii calc(ll x,ll y)
{
if(!x || !y) return mkp(0,0);
if((ll)x*y%2==0) return mkp((ll)x*y/2,(ll)x*y/2);
return mkp((ll)x*y/2+1,(ll)x*y/2);
}
pii get(const point &a,const point &b){return calc(b.x,b.y)-calc(b.x,a.y-1)-calc(a.x-1,b.y)+calc(a.x-1,a.y-1);}
ll getsize(const point &a,const point &b){return (ll)(b.x-a.x+1)*(b.y-a.y+1);}
node getmerge(node a,node b)
{
if(a.a.x>b.a.x) swap(a,b);
if(b.a.x>a.b.x) return emp;
if(b.b.y<a.a.y) return emp;
if(b.a.y>a.b.y) return emp;
return node(max(a.a.x,b.a.x),max(a.a.y,b.a.y),min(a.b.x,b.b.x),min(a.b.y,b.b.y));
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("C.in","r",stdin);
freopen("C.out","w",stdout);
#endif
int T=read();emp=node(-1,-1,-1,-1);
while(T--)
{
n=read();m=read();
p1.init();p2.init();
pii t1=calc(n,m),t2=get(p1.a,p1.b),t3=get(p2.a,p2.b);
node tmp=getmerge(p1,p2);
//tmp.write();
if(tmp.a.x==-1)
{
ans.fi=t1.fi-t2.fi-t3.fi+getsize(p1.a,p1.b);
ans.se=t1.se-t2.se-t3.se+getsize(p2.a,p2.b);
}
else
{
pii t4=get(tmp.a,tmp.b);
ans.fi=t1.fi-t2.fi-t3.fi+t4.fi+getsize(p1.a,p1.b)-getsize(tmp.a,tmp.b);
ans.se=t1.se-t2.se-t3.se+t4.se+getsize(p2.a,p2.b);
}
printf("%lld %lld\n",ans.fi,ans.se);
}
return 0;
}
D.Olya and magical square
【题目大意】
初始有一个边长为
的正方形,进行
次操作,每次选择一个正方形,将它分成四个等大的正方形。问是否能在
次操纵后从左下角的正方形走到右上角的正方形,且经过的正方形边长一样,多组数据。
【解题思路】
假设最后路径一定是贴着左、上边界,我们只需要枚举答案,然后判断是否可行即可。判断可行计算出答案需要至少切多少刀以及最多能切多少刀,可以发现答案一定很小(不到
吧)。
【参考代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF=0x3f3f3f3f3f3f3f3f;
int T,n,ans;
ll k,flag,sum,cst,val;
int main()
{
#ifndef ONLINE_JUDGE
freopen("D.in","r",stdin);
freopen("D.out","w",stdout);
#endif
scanf("%d",&T);
while(T--)
{
scanf("%d%lld",&n,&k);flag=0;sum=val=0;cst=1;
if(!k) {printf("YES %d\n",n);continue;}
for(int i=n-1;~i;--i,cst=cst*2+3)
{
sum+=((ll)1<<n-i)-1;
if(sum>k) break;
if(i>=32) val=INF;
else if(val!=INF) val+=(ll)cst*(((ll)1<<(i<<1))-1)/(ll)3;
if(sum+val>=k){ans=i;flag=1;break;}
}
if(!flag) puts("NO");
else printf("YES %d\n",ans);
}
return 0;
}
E. Sonya and Matrix Beauty
【题目大意】
给定一个只有小写字母的
矩阵,问有多少个子矩阵满足:存在一种方式,使得将每一行的字符分别重排后,这个子矩阵的每一行每一列均构成一个回文串。
【解题思路】
考虑枚举矩阵的左右边界,现在要求有多少组上下边界符合题意。观察到当且仅当两行字母集合及每个字母数量完全相同时,这两行可以对应作为列的回文串构成,我们对每一行进行哈希。接下来每一行我们得到了一个哈希值,对这些哈希值做
(插入分隔哈希值,如
),我们可以得到最大扩展,显然以每个哈希值为中心的最大扩展除以
可以累加到答案。
需要注意的是某些行不可能成为回文串(包括分割行),做 前标记即可。哈希值可以在循环枚举列的过程中处理出来。
复杂度
【参考代码】
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int N=555,bas=233;
int n,m,s[N],p[N],f[N],num[N][N];
ll ans;
ull fc[N],hs[N],a[N<<1];
char mp[N][N];
void calc()
{
for(int i=1;i<=2*n+2;++i) f[i]=0;
for(int i=n;i;--i)
{
if(s[i]<2) a[i<<1]=hs[i]; else f[i<<1]=1;
a[(i<<1)-1]=-1;
}
int len=n<<1|1,mx=0,id=0;
f[0]=f[len+1]=1;a[len]=-1;
for(int i=1;i<=len;++i)
{
if(mx>i) p[i]=min(mx-i,p[(id<<1)-i]); else p[i]=1;
while(!f[i-p[i]] && !f[i+p[i]] && a[i-p[i]]==a[i+p[i]]) ++p[i];
if(i+p[i]>=mx) mx=i+p[i],id=i;
}
for(int i=1;i<=len;++i) if(!f[i]) ans+=p[i]/2;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("CF1080E.in","r",stdin);
freopen("CF1080E.out","w",stdout);
#endif
fc[0]=1;for(int i=1;i<30;++i) fc[i]=fc[i-1]*bas;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%s",mp[i]+1);
for(int i=1;i<=m;++i)
{
for(int j=1;j<=n;++j)
{
hs[j]=0;s[j]=0;
for(int k=0;k<=26;++k) num[j][k]=0;
}
for(int j=i;j<=m;++j)
{
for(int k=1;k<=n;++k)
{
int x=mp[k][j]-'a'+1;
num[k][x]++;hs[k]+=fc[x];
if(num[k][x]&1) ++s[k]; else --s[k];
}
calc();
}
}
printf("%lld\n",ans);
return 0;
}
F. Katya and Segments Sets
【题目大意】
一共有
个集合,
个询问和总计
个二元组
(满足
),每个二元组属于一个集合
(当然可能有相同的二元组)。每个询问有四个整数
,问对于
的每个集合,是否都存在至少一个二元组满足
。
,所有数字
。询问强制在线。
【解题思路】
一道看起来是个三维偏序的题目。
我们先对这些二元组按
从大到小排序,那么对于每个询问,我们可以转化为二元组的一个前缀集合中,是否对于每个集合
都存在
。
考虑建出一棵以集合编号为下标的线段树,那么我们只需要在线段树上维护每个集合现在拥有的最小的
即可。
于是我们用可持久化线段树实现这个过程,每次新加入一个二元组我们更新对应集合的最小的
,最后询问如上即可。
复杂度 ,甚至不需要离散化。
【参考代码】
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10,M=N*40;
const int INF=0x3f3f3f3f;
int n,m,k,rt[N];
int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
struct data
{
int l,r,p;
data(int l=0,int r=0,int p=0):l(l),r(r),p(p){}
void input(){l=read();r=read();p=read();}
bool operator < (const data &x)const{return l>x.l || (l==x.l && r>x.r);}
}a[N],t;
struct Segment
{
int sz,mi[M],ls[M],rs[M];
void init(){memset(mi,0x3f,sizeof(mi));}
void copy(int x,int y){mi[x]=mi[y];ls[x]=ls[y];rs[x]=rs[y];}
void pushup(int x){mi[x]=max(mi[ls[x]],mi[rs[x]]);}
void update(int &x,int y,int l,int r,int p,int v)
{
x=++sz;copy(x,y);
if(l==r){mi[x]=min(mi[x],v);return;}
int mid=(l+r)>>1;
if(p<=mid) update(ls[x],ls[y],l,mid,p,v);
else update(rs[x],rs[y],mid+1,r,p,v);
pushup(x);
}
int query(int x,int l,int r,int L,int R)
{
if(!x) return INF;
if(L<=l && r<=R) return mi[x];
int mid=(l+r)>>1,ret=0;
if(L<=mid) ret=max(ret,query(ls[x],l,mid,L,R));
if(R>mid) ret=max(ret,query(rs[x],mid+1,r,L,R));
return ret?ret:INF;
}
}tr;
int main()
{
#ifndef ONLINE_JUDGE
freopen("CF1080F.in","r",stdin);
freopen("CF1080F.out","w",stdout);
#endif
n=read();m=read();k=read();
for(int i=1;i<=k;++i) a[i].input();
sort(a+1,a+k+1);tr.init();
for(int i=1;i<=k;++i) tr.update(rt[i],rt[i-1],1,n,a[i].p,a[i].r);
for(int i=1;i<=m;++i)
{
int l=read(),r=read(),x=read(),y=read();
int p=lower_bound(a+1,a+k+1,data(x,0,0))-a-1;
int mx=tr.query(rt[p],1,n,l,r);
puts(mx<=y?"yes":"no");
fflush(stdout);
}
return 0;
}
【总结】
比赛时巨蒻,需要多打一些qwq。