传送门
并没有找到难度评级但感觉是
d
i
v
3
div3
div3场。
A题
题意:一个单词的价值是里面大写字母的个数,一篇文章的价值是里面所有单词的价值的最大值。
求一篇文章的价值。
思路:按照题意模拟。
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
char s[205];
int main(){
int t,ans=0;
cin>>t;
while(~scanf("%s",s)){
int cnt=0;
for(ri i=0,up=strlen(s);i<up;++i){
if(s[i]>='A'&&s[i]<='Z')++cnt;
}
ans=max(ans,cnt);
}
cout<<ans;
return 0;
}
B题
传送门
题意:给你一个
n
∗
m
n*m
n∗m的三色方阵,问是否满足这个方阵被三种颜色均分成三个长宽都相等的子方阵。
思路:按照题意模拟。
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int N=105;
const int rlen=1<<18|1;
inline char gc(){
return getchar();
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
int n,m;
char s[105][105];
inline void check1(){
char tmp=s[1][1];
if(s[1][1]==s[n/3+1][1]||s[n/3+1][1]==s[n/3*2+1][1]||s[1][1]==s[n/3*2+1][1])return;
bool f=1;
for(ri i=1;i<=n/3;++i){
for(ri j=1;j<=m;++j){
if(s[i][j]!=tmp){
f=0;
break;
}
}
if(!f)break;
}
if(!f)return;
tmp=s[n/3+1][1];
for(ri i=n/3+1;i<=n/3*2;++i){
for(ri j=1;j<=m;++j){
if(s[i][j]!=tmp){
f=0;
break;
}
}
if(!f)break;
}
if(!f)return;
tmp=s[n/3*2+1][1];
for(ri i=n/3*2+1;i<=n;++i){
for(ri j=1;j<=m;++j){
if(s[i][j]!=tmp){
f=0;
break;
}
}
if(!f)break;
}
if(!f)return;
puts("YES");
exit(0);
}
inline void check2(){
char tmp=s[1][1];
if(s[1][1]==s[1][m/3+1]||s[1][m/3+1]==s[1][m/3*2+1]||s[1][1]==s[1][m/3*2+1])return;
bool f=1;
for(ri i=1;i<=n;++i){
for(ri j=1;j<=m/3;++j){
if(s[i][j]!=tmp){
f=0;
break;
}
}
if(!f)break;
}
if(!f)return;
tmp=s[1][m/3+1];
for(ri i=1;i<=n;++i){
for(ri j=m/3+1;j<=m/3*2;++j){
if(s[i][j]!=tmp){
f=0;
break;
}
}
if(!f)break;
}
if(!f)return;
tmp=s[1][m/3*2+1];
for(ri i=1;i<=n;++i){
for(ri j=m/3*2+1;j<=m;++j){
if(s[i][j]!=tmp){
f=0;
break;
}
}
if(!f)break;
}
if(!f)return;
puts("YES");
exit(0);
}
int main(){
n=read(),m=read();
for(ri i=1;i<=n;++i)scanf("%s",s[i]+1);
if(n%3&&m%3)return puts("NO"),0;
if(!(n%3))check1();
if(!(m%3))check2();
puts("NO");
return 0;
}
C题
传送门
题意:你有一个
a
∗
b
a*b
a∗b的方格和
n
n
n个长宽为
x
i
,
y
i
x_i,y_i
xi,yi的印章,要求你放两个印章上去,它们不能相交且印章覆盖总面积最大,每个印章可以旋转
90
°
90\degree
90°。
思路:按照题意模拟。
代码:
#include<bits/stdc++.h>
#define ri register int
#define fi first
#define se second
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
typedef pair<int,int> pii;
const int N=105;
int n,a,b,tot=0,ans=0;
struct Node{int a,b,id;}A[N<<1];
inline void update(const Node&A,const Node&B){
if(A.id==B.id)return;
if(A.a>a||B.a>a||A.b>b||B.b>b)return;
if(A.a+B.a<=a||A.b+B.b<=b)ans=max(ans,A.a*A.b+B.a*B.b);
}
int main(){
n=read(),a=read(),b=read();
for(ri x,y,i=1;i<=n;++i)x=read(),y=read(),A[++tot]=(Node){x,y,i},A[++tot]=(Node){y,x,i};
for(ri i=1;i<=tot;++i)for(ri j=1;j<=tot;++j)update(A[i],A[j]);
cout<<ans;
return 0;
}
D题
传送门
题意:规定一个数的价值是其后缀0个数,现在要求你从
n
n
n个数中选
k
k
k个出来乘起来,问乘积的价值的最大值。
n
≤
200
,
a
i
≤
1
e
18
n\le200,a_i\le1e18
n≤200,ai≤1e18
思路:
显然只用关心
2
2
2和
5
5
5的个数。
考虑
d
p
dp
dp,定义状态
f
i
,
j
,
k
f_{i,j,k}
fi,j,k表示前
i
i
i个选了
j
j
j个,
5
5
5的个数为
k
k
k时
2
2
2的个数的最大值。
然后随便转移一下最后取一个最值就完了。
代码:
#include<bits/stdc++.h>
#define ri register int
#define fi first
#define se second
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
typedef long long ll;
inline ll read(){
ll ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
typedef pair<int,int> pii;
const int N=205,K=7005;
int n,k,f[2][N][K],tmp=0;
inline pii solve(ll x){
int c1=0,c2=0;
while(x==x/2*2)++c1,x/=2;
while(x==x/5*5)++c2,x/=5;
return pii(c1,c2);
}
int main(){
n=read(),k=read();
int sum=0;
pii a;
memset(f[tmp],-1,sizeof(f[tmp]));
f[tmp][0][0]=0;
for(ri tt=1;tt<=n;++tt){
ll x=read();
a=solve(x);
sum+=a.se;
tmp^=1;
memcpy(f[tmp],f[tmp^1],sizeof(f[tmp]));
for(ri j=1;j<=k;++j)for(ri i=a.se;i<=sum;++i)if(~f[tmp^1][j-1][i-a.se])f[tmp][j][i]=max(f[tmp][j][i],f[tmp^1][j-1][i-a.se]+a.fi);
}
int ans=0;
for(ri j=0;j<=k;++j)for(ri i=0;i<=sum;++i)ans=max(ans,min(i,f[tmp][j][i]));
cout<<ans;
return 0;
}
E题
传送门
题意:有一个函数
f
(
a
,
b
)
:
f(a,b):
f(a,b):
f
(
a
,
0
)
=
0
,
f
(
a
,
b
>
0
)
=
f
(
a
,
b
−
g
c
d
(
a
,
b
)
)
+
1
f(a,0)=0,f(a,b>0)=f(a,b-gcd(a,b))+1
f(a,0)=0,f(a,b>0)=f(a,b−gcd(a,b))+1
问
f
(
x
,
y
)
f(x,y)
f(x,y)等于多少
a
,
b
≤
1
e
12
a,b\le1e12
a,b≤1e12
思路:
发现对于
a
,
b
,
g
=
g
c
d
(
a
,
b
)
a,b,g=gcd(a,b)
a,b,g=gcd(a,b),
f
(
a
,
b
)
=
f
(
a
g
,
b
g
)
f(a,b)=f(\frac ag,\frac bg)
f(a,b)=f(ga,gb)
于是我们模拟一下这个过程,每次求出当前的
b
b
b减几之后会跟当前的
a
a
a的
g
c
d
gcd
gcd大于
1
1
1即可。
实现可以每次暴力求出
a
a
a的所有约数来判断。
代码:
#include<bits/stdc++.h>
#define ri register int
#define fi first
#define se second
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
typedef long long ll;
inline ll read(){
ll ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
ll x,y;
vector<ll>divv;
inline void solve(ll x){
if(x==1){divv.push_back(1);return;}
divv.clear();
for(ri i=2;(ll)i*i<=x;++i){
if(x!=x/i*i)continue;
divv.push_back(i);
if((ll)i*i!=x)divv.push_back(x/i);
}
divv.push_back(x);
sort(divv.begin(),divv.end());
}
int main(){
x=read(),y=read();
ll ans=0;
solve(x);
while(y>=divv[0]){
if(x==1)break;
solve(x);
ll rs=divv[0],tim=y-y/rs*rs;
for(ri i=1,up=divv.size();i<up;++i){
if(divv[i]>y)break;
if(y-y/divv[i]*divv[i]<=tim)rs=divv[i],tim=y-y/rs*rs;
}
ans+=tim,y/=rs,x/=rs;
solve(x);
}
cout<<ans+y;
return 0;
}
F题
传送门
题意:
定义函数
f
(
a
)
,
a
为
数
列
=
数
列
b
,
b
i
=
∑
j
=
1
i
a
i
f(a),a为数列=数列b,b_i=\sum_{j=1}^i a_i
f(a),a为数列=数列b,bi=∑j=1iai
现在有一个初始数列
a
a
a和一个数
k
k
k,问对这个数列调用几次
f
f
f函数之后序列中会存在一个数不小于
k
k
k,
∣
a
∣
≤
200000
,
k
≤
1
e
18
|a|\le200000,k\le1e18
∣a∣≤200000,k≤1e18
思路:
显然特判掉次数为
0
,
1
0,1
0,1的情况然后二分答案,
c
h
e
c
k
check
check的话直接看最后一个数是否小于
k
k
k即可。
手推一波公式会发现初始数列中每个数对于要求值贡献的系数是组合数,因此我们暴力加就是了,注意可能会爆
l
o
n
g
l
o
n
g
long long
longlong。
代码:
#include<bits/stdc++.h>
#define ri register int
#define fi first
#define se second
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
typedef long long ll;
inline ll read(){
ll ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
const int N=2e5+5;
int n;
ll k,a[N];
inline bool check(ll tim){
long double sum=0,fac=1;
for(ri i=1;i<=n;++i){
if(i^1)fac=fac*(i+tim-2);
if(i^1)fac/=(i-1);
if(fac>k||fac<0)fac=k;
if(fac*a[n-i+1]<0)return 1;
sum+=fac*a[n-i+1];
if(sum>=k||sum<0)return 1;
}
return 0;
}
int main(){
n=read(),k=read();
for(ri i=1;i<=n;++i){
a[i]=read();
if(a[i]>=k)return puts("0"),0;
}
ll sum=0;
for(ri i=1;i<=n;++i)sum+=a[i];
if(sum>=k)return puts("1"),0;
ll l=2,r=k,res=k;
while(l<=r){
ll mid=l+r>>1;
if(check(mid))r=mid-1,res=mid;
else l=mid+1;
}
cout<<res;
return 0;
}
G题
传送门
题意:现在有
n
n
n个分段函数,
f
i
(
x
)
f_i(x)
fi(x)有
6
6
6个参数
x
1
,
x
2
,
y
1
,
a
,
b
,
y
2
x_1,x_2,y_1,a,b,y_2
x1,x2,y1,a,b,y2
f
(
x
)
=
y
1
,
0
≤
x
≤
x
1
f(x)=y1,0\le x\le x_1
f(x)=y1,0≤x≤x1
f
(
x
)
=
a
x
+
b
,
x
1
<
x
≤
x
2
f(x)=ax+b,x_1<x\le x_2
f(x)=ax+b,x1<x≤x2
f
(
x
)
=
y
2
,
x
2
<
x
f(x)=y2,x_2<x
f(x)=y2,x2<x
现在有
m
m
m次询问,每次给出
l
,
r
,
x
l,r,x
l,r,x,求
∑
i
=
l
r
f
i
(
x
)
\sum_{i=l}^rf_i(x)
∑i=lrfi(x),强制在线。
思路:显然需要维护一个
∑
i
=
1
k
f
i
(
x
)
\sum_{i=1}^kf_i(x)
∑i=1kfi(x)
考虑到将
f
(
x
)
f(x)
f(x)稍加改动:
f
(
x
)
=
0
x
+
y
1
,
0
≤
x
≤
x
1
f(x)=0x+y1,0\le x\le x_1
f(x)=0x+y1,0≤x≤x1
f
(
x
)
=
a
x
+
b
,
x
1
<
x
≤
x
2
f(x)=ax+b,x_1<x\le x_2
f(x)=ax+b,x1<x≤x2
f
(
x
)
=
0
x
+
y
2
,
x
2
<
x
f(x)=0x+y2,x_2<x
f(x)=0x+y2,x2<x
这启发我们最后答案等于
A
x
+
B
Ax+B
Ax+B,因此我们只需要维护
A
,
B
A,B
A,B的和即可。
这个可以用主席树实现。
代码:
#include<bits/stdc++.h>
#define ri register int
#define fi first
#define se second
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
typedef long long ll;
const int N=75005,M=N*120;
int rt[N],n;
struct data{
ll a,b;
data(ll a=0,ll b=0):a(a),b(b){}
friend inline data operator+(const data&a,const data&b){return data(a.a+b.a,a.b+b.b);}
friend inline data operator-(const data&a,const data&b){return data(a.a-b.a,a.b-b.b);}
};
namespace SGT{
#define lc (son[p][0])
#define rc (son[p][1])
#define mid (l+r>>1)
data sum[M];
int son[M][2],tot=0;
inline void update(int&p,int o,int l,int r,int ql,int qr,data v){
p=++tot,lc=son[o][0],rc=son[o][1],sum[p]=sum[o];
if(ql<=l&&r<=qr){sum[p]=sum[p]+v;return;}
if(qr<=mid)update(lc,son[o][0],l,mid,ql,qr,v);
else if(ql>mid)update(rc,son[o][1],mid+1,r,ql,qr,v);
else update(lc,son[o][0],l,mid,ql,mid,v),update(rc,son[o][1],mid+1,r,mid+1,qr,v);
}
inline data query(int&p,int l,int r,int k){return !p?data(0,0):(l==r?sum[p]:sum[p]+(k<=mid?query(lc,l,mid,k):query(rc,mid+1,r,k)));}
#undef lc
#undef rc
#undef mid
}
int main(){
n=read();
int lim=200001;
for(ri i=1,x1,x2,y1,a,b,y2;i<=n;++i){
x1=read(),x2=read(),y1=read(),a=read(),b=read(),y2=read();
rt[i]=rt[i-1];
SGT::update(rt[i],rt[i],0,lim,0,x1,data(0,y1));
SGT::update(rt[i],rt[i],0,lim,x1+1,x2,data(a,b));
SGT::update(rt[i],rt[i],0,lim,x2+1,lim,data(0,y2));
}
ll lastans=0;
data tmp;
for(ri l,r,x,tt=read();tt;--tt){
l=read(),r=read(),x=(lastans+read())%1000000000;
tmp=SGT::query(rt[r],0,lim,min(x,lim))-SGT::query(rt[l-1],0,lim,min(x,lim));
cout<<(lastans=tmp.a*x+tmp.b)<<'\n';
}
return 0;
}