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)

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


最大公约数

 

观察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;
}