E 走呀走

二维DP。
#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
ll a[2000][2000];
ll ans[2000][2000];
int main(){
ll n,m;
scanf("%lld%lld",&n,&m);
for(ll i=1;i<=n;i++){
for(ll j=1;j<=m;j++){
scanf("%lld",&a[i][j]);
//第i行 第j个
}
}
ans[1][1]=a[1][1];
for(ll i=1;i<=n;i++){
for(ll j=1;j<=m;j++){
ans[i][j]=max(max(
ans[i-1][j]+a[i][j],
ans[i][j-1]+a[i][j]),
ans[i][j]);
}
}
cout<<ans[n][m]<<endl;
return 0;
}
F 关灯问题(二)

埃氏筛法。
#include<cstdio>
#include<iostream>
using namespace std;
const int MAXN=2e6;
int n;//上界
int cnt[MAXN];
void init(int val){
for(int i=1;i<=n&&i*val<=n;i++){
cnt[i*val]++;
}
}
int main(){
int m,q;
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=m;i++){
init(i);
}
for(int i=1;i<=q;i++){
int val;
scanf("%d",&val);
printf("%d\n",cnt[val]);
}
return 0;
}
H 觉悟排列(Easy Version)

打表。暴力也可以(更简单)

J 最大公约数


观察z的式子,可以发现z=x/y,然后进行修改。总结样例,不难发现答案为x/gcd(x,y)*y/gcd(x,y)。
#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
ll gcd(ll a,ll b){
if(b>a)swap(a,b);
if(b==0)return a;
return gcd(a%b,b);
}
int main(){
ll t;
scanf("%lld",&t);
for(ll i=1;i<=t;i++){
ll x,y;
scanf("%lld%lld",&x,&y);
ll val=gcd(x,y);
ll num=(x/val)*(y/val);
cout<<num<<endl;
}
return 0;
}
l 植物大战僵尸

带修主席树。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=3e5+10;
int n,m,tot,sz,num,a[N],b[N],rt[N],s[N],sum[N*300],ls[N*300],rs[N*300],rootl[N],rootr[N],cntl,cntr;
struct node{
int l,r,k,op;
}q[N];
int get(int x){return lower_bound(b+1,b+sz+1,x)-b;}
int lowbit(int x){return x&(-x);}
struct Tree{
void update(int &o,int pre,int l,int r,int x){
o=++tot;
sum[o]=sum[pre]+1;
ls[o]=ls[pre];
rs[o]=rs[pre];
if(l==r) return;
int mid=l+r>>1;
if(x<=mid) update(ls[o],ls[pre],l,mid,x);
else update(rs[o],rs[pre],mid+1,r,x);
}
void add_update(int &o,int l,int r,int x,int val){
if(o==0) o=++tot;
sum[o]+=val;
if(l==r) return;
int mid=l+r>>1;
if(x<=mid) add_update(ls[o],l,mid,x,val);
else add_update(rs[o],mid+1,r,x,val);
}
void add_update(int k,int val){
int x=get(a[k]);int y=get(val);
a[k]=val;
while(k<=n){
add_update(s[k],1,sz,x,-1);
add_update(s[k],1,sz,y,1);
k+=lowbit(k);
}
}
int query(int last,int now,int l,int r,int x){
if(l==r) return l;
int cnt=sum[ls[now]]-sum[ls[last]];
for(int i=1;i<=cntl;++i) cnt-=sum[ls[rootl[i]]];
for(int i=1;i<=cntr;++i) cnt+=sum[ls[rootr[i]]];
int mid=l+r>>1;
if(cnt>=x){
for(int i=1;i<=cntl;++i) rootl[i]=ls[rootl[i]];
for(int i=1;i<=cntr;++i) rootr[i]=ls[rootr[i]];
return query(ls[last],ls[now],l,mid,x);
}else{
for(int i=1;i<=cntl;++i) rootl[i]=rs[rootl[i]];
for(int i=1;i<=cntr;++i) rootr[i]=rs[rootr[i]];
return query(rs[last],rs[now],mid+1,r,x-cnt);
}
}
int kth(int l,int r,int k){
cntl=cntr=0;
for(int i=l-1;i;i-=lowbit(i)) rootl[++cntl]=s[i];
for(int i=r;i;i-=lowbit(i)) rootr[++cntr]=s[i];
int ans=query(rt[l-1],rt[r],1,sz,k);
return b[ans];
}
}tr;
int main(){
scanf("%d%d",&n,&m);//n个高坚果 m个操作
for(int i=1;i<=n;++i) scanf("%d",&a[i]),b[++sz]=a[i];
for(int i=1;i<=m;++i){
int opt;
scanf("%d",&opt);//m个操作
if(opt==1){//查找
q[i].op=1;
q[i].l=1;
q[i].r=n;
scanf("%d",&q[i].k);
}else{//修改
q[i].op=2;
scanf("%d%d",&q[i].l,&q[i].r);b[++sz]=q[i].r;
}
}
sort(b+1,b+sz+1);
int num=unique(b+1,b+sz+1)-b-1;
sz=num;
for(int i=1;i<=n;++i) tr.update(rt[i],rt[i-1],1,sz,get(a[i]));
for(int i=1;i<=m;++i){
if(q[i].op==1){
printf("%d\n",tr.kth(q[i].l,q[i].r,q[i].k));
}else{
tr.add_update(q[i].l,q[i].r);
}
}
return 0;
}
Q 杠杆の套娃

利用二叉树的性质,发现递归有着同样的性质。
#include<cstdio>
#include<iostream>
using namespace std;
bool solve(int &w){
int w1,w2,dis1,dis2;
bool canSolve1=1,canSolve2=1;//两端能否平衡
scanf("%d%d%d%d",&w1,&dis1,&w2,&dis2);//当前杠杆两端的重量
if(w1==0){
canSolve1=solve(w1);
}
if(w2==0){
canSolve2=solve(w2);
}
w=w1+w2;//总重量
return canSolve1&&canSolve2&&(w1*dis1==w2*dis2);
}
int main(){
int n;
scanf("%d",&n);
int w;
if(solve(w)){
printf("YES\n");
}else{
printf("NO\n");
}
return 0;
}
