T 1 T_1 T1——slon(1783)
Description:
对于一个表达式
S
S
S,形如
5
+
x
∗
(
3
+
2
)
,
x
+
3
∗
x
+
4
∗
(
5
+
3
∗
(
2
+
x
−
2
∗
x
)
)
5+x*(3+2),x+3*x+4*(5+3*(2+x-2*x))
5+x∗(3+2),x+3∗x+4∗(5+3∗(2+x−2∗x)),求最小的非负数
x
x
x,使得表达式的值对
M
M
M取模后为
P
P
P。
注意:
x
x
x的指数不超过
1
1
1,且一个运算符号的两边一定有操作数。
∣
S
∣
≤
1
0
5
,
0
≤
P
≤
M
−
1
,
M
≤
1
0
6
|S|\le10^5,0\le P\le M-1,M\le 10^6
∣S∣≤105,0≤P≤M−1,M≤106
Solution:
- 表达式求值模拟题(
沙雕模拟题) - 做这种表达式求值问题,无非就是栈模拟,以及重载运算符和写一些关键函数,可以大大缩短码量和实现难度。
- 最后,要求对
M
M
M取模的情况,但发现此题的
M
M
M比较小,那么直接
f
o
r
for
for找即可(
扩展欧几里得)。
Code:
#include<bits/stdc++.h>
using namespace std;
#define SREP(i,f,t) for(int i=(f),i##_end_=(t);i<i##_end_;++i)
const int N=100002;
int n,P,mod;
int Top,top;
char op[N],str[N];
struct node{
int k,b;
}Stk[N];
node operator+(node x,node y){
node res;
res.k=(x.k+y.k)%mod;
res.b=(x.b+y.b)%mod;
return res;
}
node operator-(node x,node y){
node res;
res.k=(x.k-y.k)%mod;
res.b=(x.b-y.b)%mod;
return res;
}
node operator*(node x,node y){
node res;
res.k=(1ll*x.k*y.b+1ll*x.b*y.k)%mod;
res.b=1ll*x.b*y.b%mod;
return res;
}
node calc(node A,node B,char c){
if(c=='*') return A*B;
if(c=='+') return A+B;
if(c=='-') return A-B;
}
bool Cmp(char a,char b){
if(a=='(' or b=='(') return 0;
if(b==')' or b=='+' or b=='-' or a=='*') return 1;
return 0;
}
int main(){
// freopen("slon.in","r",stdin);
// freopen("slon.out","w",stdout);
scanf("%s%d%d",str,&P,&mod);
int n=strlen(str);
str[n]=')';op[top++]='(';
SREP(i,0,n+1){
if(str[i]=='x') Stk[Top++]=(node){1,0};
else if(str[i]>='0' and str[i]<='9'){
int x=(str[i]-'0')%mod;
while(str[i+1]>='0' and str[i+1]<='9') x=(x*10+str[++i]-'0')%mod;
Stk[Top++]=(node){0,x};
}
else{
while(Cmp(op[top-1],str[i])){
node x=Stk[--Top],y=Stk[--Top];
char c=op[--top];
Stk[Top++]=calc(y,x,c);
}
if(str[i]==')') --top;
else op[top++]=str[i];
}
}
node ans=Stk[--Top];
SREP(i,0,mod){
if((1ll*ans.k*i+ans.b-P)%mod==0){
printf("%d\n",i);
break;
}
}
return 0;
}
T 2 T_2 T2——bad(3835)
Description:
有一个长度为
n
n
n的序列
A
A
A。
定义一个坏对
(
i
,
j
)
(i,j)
(i,j)当且仅当
i
<
j
,
A
i
m
o
d
  
A
j
=
K
i<j,A_i \mod A_j=K
i<j,AimodAj=K。
求有多少个区间满足区间不存在坏对。
n
,
A
i
≤
1
0
5
,
0
≤
K
≤
1
0
5
n,A_i\le 10^5,0\le K \le 10^5
n,Ai≤105,0≤K≤105
Solution:
- 首先,坏对的定义,我们可以去掉模数,即 ( i , j ) , i < j , A i = A j ∗ x + K (i,j),i<j,A_i=A_j*x+K (i,j),i<j,Ai=Aj∗x+K
- 又因为 A i ≤ 1 0 5 A_i \le 10^5 Ai≤105,那么,我们可以预处理出与 i i i匹配坏对的数
- 那么我们在遍历时,对于第 i i i个数,我们要更新与之可以匹配坏对的数
- 那么对答案的贡献即为 i − l a s t i-last i−last
- 这样复杂度为 Θ ( n ⋅ n ) \Theta(n\cdot \sqrt n) Θ(n⋅n)
Code:
#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t) for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define ll long long
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
template<class T>inline void rd(T &x){
x=0;char c;
while((c=getchar())<48);
do x=(x<<1)+(x<<3)+(c^48);
while((c=getchar())>47);
}
const int N=1e5+2;
int n,m;
int A[N];
int tot;
struct node{
int l,r;
bool operator<(const node &_)const{
return r<_.r;
}
}B[N];
struct p50{
void solve(){
tot=0;
REP(i,2,n) REP(j,1,i) if(A[j]%A[i]==m) B[++tot]=(node){j,i};
sort(B+1,B+1+tot);
int ans=n;
REP(l,1,n) REP(r,l+1,n) {
bool flag=1;
REP(i,1,tot) {
if(r<B[i].l)break;
if(l<=B[i].l and B[i].r<=r){flag=0;break;}
}
ans+=flag;
}
printf("%d\n",ans);
}
}p1;
struct p70{
vector<int>Son[N];
int mx[N];
void solve(){
SREP(i,1,N) for(int j=i;j<N;j+=i) Son[j].push_back(i);
ll ans=0;
int last=0;
REP(i,1,n){
chkmax(last,mx[A[i]]);
ans+=i-last;
SREP(j,0,Son[A[i]].size()) chkmax(mx[Son[A[i]][j]],i);
}
printf("%lld\n",ans);
}
}p2;
struct p100{
vector<int>Son[N];
int mx[N];
void solve(){
SREP(i,m+1,N) for(int j=0;j+m<N;j+=i)Son[j+m].push_back(i);
ll ans=0;
int last=0;
REP(i,1,n){
if(A[i]>m) chkmax(last,mx[A[i]]);
ans+=i-last;
SREP(j,0,Son[A[i]].size()) chkmax(mx[Son[A[i]][j]],i);
}
printf("%lld\n",ans);
}
}p3;
int main(){
// freopen("bad.in","r",stdin);
// freopen("bad.out","w",stdout);
rd(n),rd(m);
REP(i,1,n) rd(A[i]);
if(n<=1000)p1.solve();
else if(!m)p2.solve();
else p3.solve();
return 0;
}
T 3 T_3 T3——holiday(3064)
Description:
有一排城市,编号为0~n-1,对于城市
i
i
i,只与城市
i
−
1
i-1
i−1和城市
i
+
1
i+1
i+1相连,且每个城市有一个价值
A
i
A_i
Ai。
现在从城市
s
s
s出发,有
d
d
d天时间。
规定相邻城市之间的花费和得到一个城市的价值的花费为
1
1
1天。
求最大价值。
2
≤
n
≤
1
0
5
,
0
≤
A
i
≤
1
0
9
,
0
≤
s
≤
n
−
1
,
0
≤
d
≤
2
⋅
n
+
n
2
2\le n\le10^5,0\le A_i\le10^9,0\le s\le n-1,0\le d \le 2\cdot n+\frac{n}{2}
2≤n≤105,0≤Ai≤109,0≤s≤n−1,0≤d≤2⋅n+2n
Solution:
- 写部分分时,不难发现有单调性,对于每个起点 l l l,都有最优解的终点 r r r,
- 那么可以分治一个区间,进而枚举左端点,来找最优解的右端点,再用主席树来查询当前区间的贡献
- 复杂度为 Θ ( n log 2 n ) \Theta(n\log ^2n) Θ(nlog2n)
Code:
#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t) for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define LL long long
template<class T>inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
const int N=1e5+2,INF=0x3f3f3f3f;
int n,s,d;
int A[N];
struct p30{
void solve(){
LL ans=0;
SREP(S,0,1<<n){
LL val=0;
int sum=0;
int l=s,r=s;
SREP(i,0,n) if(S&(1<<i)) {
if(i<=s) chkmin(l,i);
if(i>=s) chkmax(r,i);
sum++;
val+=A[i];
}
if(l!=INF and r!=-INF) {
if(s-l<r-s) sum+=(s-l)*2+r-s;
else sum+=s-l+2*(r-s);
}
if(sum<=d)chkmax(ans,val);
}
printf("%lld\n",ans);
}
}p1;
struct p50{
void solve(){
}
}p2;
struct p70{
priority_queue<int>Q;
void solve(){
LL res=0,ans=0;
SREP(i,0,n){
Q.push(-A[i]);res+=A[i];
if(i>=d)break;
while(i+Q.size()>d)res+=Q.top(),Q.pop();
chkmax(ans,res);
}
printf("%lld\n",ans);
}
}p3;
struct p100{
int B[N],tot;
int Lson[N*20],Rson[N*20],root[N],tim;
int cnt[N*20];
LL sum[N*20];
void Update(int &p,int f,int l,int r,int x){
p=++tim;
if(l==r){
cnt[p]=cnt[f]+1;
sum[p]=sum[f]+B[x];
return;
}
int mid=(l+r)>>1;
Lson[p]=Lson[f],Rson[p]=Rson[f];
if(x<=mid) Update(Lson[p],Lson[f],l,mid,x);
else Update(Rson[p],Rson[f],mid+1,r,x);
cnt[p]=cnt[Lson[p]]+cnt[Rson[p]];
sum[p]=sum[Lson[p]]+sum[Rson[p]];
}
LL Query(int p,int f,int k,int l,int r){
if(l==r)return 1ll*B[l]*min(k,cnt[p]);
int mid=(l+r)>>1;
int tmp=cnt[Rson[p]]-cnt[Rson[f]];
if(k<=tmp) return Query(Rson[p],Rson[f],k,mid+1,r);
else return sum[Rson[p]]-sum[Rson[f]]+Query(Lson[p],Lson[f],k-tmp,l,mid);
}
LL ans;
void Solve(int ll,int lr,int rl,int rr){
int rmid=(rl+rr)>>1,lmid=lr;
LL Mx=0;
REP(i,ll,lr){
int res=(rmid-i)+min(s-i,rmid-s);
if(d-res>0) if(chkmax(Mx,Query(root[rmid],root[i-1],d-res,1,tot))) lmid=i;
}
chkmax(ans,Mx);
if(rl<=rmid-1) Solve(ll,lmid,rl,rmid-1);
if(rmid+1<=rr) Solve(lmid,lr,rmid+1,rr);
}
void solve(){
SREP(i,0,n)B[++tot]=A[i];
sort(B+1,B+1+tot);
tot=unique(B+1,B+1+tot)-B-1;
DREP(i,n,1) A[i]=lower_bound(B+1,B+1+tot,A[i-1])-B;
REP(i,1,n) Update(root[i],root[i-1],1,tot,A[i]);
s++;
Solve(1,s,s,n);
printf("%lld\n",ans);
}
}p4;
int main(){
// freopen("holiday.in","r",stdin);
// freopen("holiday.out","w",stdout);
scanf("%d%d%d",&n,&s,&d);
SREP(i,0,n) scanf("%d",&A[i]);
if(n<=20)p1.solve();
// else if(n<=3000)p2.solve();
else if(!s)p3.solve();
else p4.solve();
return 0;
}