美團筆試覆盤

啥也不說了,菜就得捱打。

題目大意:

給定一個數組a[i],長度爲n<=1e5,你必須在其中刪除一個數,使得最長連續上升子序列最長。問你最長多長。

思路:

dp[i][0]表示i-1之前都沒有刪除的以i爲結尾的最長上升子串的長度,dp[i][1]表示i-1之前已經刪除過的以i爲結尾的最長上升子串的長度。(比賽種我用的是dp[i][1]表示在i點刪除,dp[i][2]表示在i之前刪除,這樣也可以,但是轉移比較麻煩,還是上面這種寫法最方便)。

然後遞推的時候注意,如果刪除了i-1,你必須與i-2這個狀態進行比較,就是考慮a[i]和a[i-2]的大小關係,具體看代碼

#include <stdio.h>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int maxn=1e5+10;
int a[maxn];
int dp[maxn][2];
const int INF=0x3f3f3f3f;

signed main(){
	int n;
	freopen("E:\\mingw\\in.txt","r",stdin);
    freopen("E:\\mingw\\out2.txt","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	dp[1][1]=0;
	dp[1][0]=1;
	for(int i=2;i<=n;i++){
		if(a[i]>a[i-1]){
			dp[i][1]=max(dp[i-1][1]+1,dp[i-1][0]);
			dp[i][0]=dp[i-1][0]+1;
		}
		else{
			dp[i][0]=1;
			if(a[i]>a[i-2]){
				dp[i][1]=max(1,dp[i-2][0]+1);
			}
			else{
				dp[i][1]=1;
			}
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		ans=max(ans,dp[i][1]);
	}
	printf("%d\n",ans);
	return 0;
}

題目大意:

給定n個任務,每個任務有k個子任務,每個大大任務的k個子任務耗時都是一定的,每完成一個子任務,得到p的分,如果完成了一個大任務的所有小任務,得到p*k+q的分,現在你有m的時間,問你最多能得到多少分?

m<=2e9,每個子任務t<=1e6,n,k<=100

思路:

直接枚舉完成多少個大任務,在完成多少個大任務後,對小任務排序,因爲我不會再完成新的大任務了,所以我肯定是先將剩下的大任務中耗時最小的小任務都完成,然後去完成第二小的,然後第三小.......這樣小任務就可以貪心解決了

#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#define int long long 
using namespace std;

const int maxn=100+10;
int cost[maxn];
signed main(){
	int n,k,m;
	scanf("%lld%lld%lld",&n,&k,&m);
	int sum=0;
	for(int i=1;i<=k;i++){
		scanf("%lld",&cost[i]);
		sum+=cost[i];
	}
	sort(cost+1,cost+n+1);
	int p,q;
	scanf("%lld%lld",&p,&q);
	int cnt=min(n,m/sum);
	if(cnt>=n){
		printf("%lld\n",n*(p*k+q));
		return 0;
	}
	int ans=0;
	for(int i=0;i<=cnt;i++){
		int temp=m-i*sum;
		int cur=i*(p*k+q);
		for(int j=1;j<=k;j++){
			for(int t=i+1;t<=n;t++){
				if(temp>=cost[j]){
					temp-=cost[j];
					cur+=p;
				}
				else{
					temp=0;break;
				}
			}
			if(!temp)break;
		}
		ans=max(ans,cur);
	}
	printf("%lld\n",ans);
	return 0;
}

題目大意:

給定一個無向圖,現在你從點s出發,向其他點跑,路徑一定選擇最短路,問你一共跑k米,到達的點數的個數是多少?注意在路中間停下來也算點的個數。

n<=1e5,m<=1e5.

思路:

直接dijkstra求出s到每個點的最短路的距離,然後你只需要思考一個問題:如果沒有點恰好爲k,那是不是所有的點都在邊上?這時候直接統計;如果有點的距離恰好爲k,那是否會引起計數的重複?如果你記錄邊的話,計數是絕對會重複的,所以再加一個重複個數的計數即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;

const int maxn=1e5+10;
int dis[maxn];
struct HeapNode{
    int u,d;
    HeapNode(int _u,int _d):u(_u),d(_d){}
    bool operator < (const HeapNode &rhs)const{
        return d>rhs.d;
    }
};
int vis[maxn];
struct Edge{
    int u,v,cost;
    Edge(int u,int v,int cost):u(u),v(v),cost(cost){}
};
vector<int>G[maxn];
vector<Edge>edges;
void add_edges(int u,int v,int cost){
    edges.push_back(Edge(u,v,cost));
    edges.push_back(Edge(v,u,cost));
    int sz=edges.size();
    G[u].push_back(sz-2);
    G[v].push_back(sz-1);
}
const int INF=1e9;
int n,m,k;
void Dijkstra(int s){
    memset(vis,0,sizeof(vis));
    for(int i=0;i<=n;i++)dis[i]=INF;
    dis[s]=0;
    vis[s]=1;
    priority_queue<HeapNode>Q;
    Q.push(HeapNode(s,0));
    while(Q.size()){
        HeapNode x=Q.top();Q.pop();
        int u=x.u;
        for(int i=0;i<G[u].size();i++){
            Edge &e=edges[G[u][i]];
            int v=e.v;
            if(dis[v]>dis[u]+e.cost){
                dis[v]=dis[u]+e.cost;
                if(!vis[v]){
                    vis[v]=1;
                    Q.push(HeapNode(v,dis[v]));
                }
            }
        }
    }
}

signed main(){
    int s;
    scanf("%d%d%d",&n,&m,&s);
    for(int i=1;i<=m;i++){
        int u,v,cost;
        scanf("%d%d%d",&u,&v,&cost);
        add_edges(u,v,cost);
    }
    scanf("%d",&k);
    Dijkstra(s);
    int ans=0;
    int cnt=0;
    for(int u=1;u<=n;u++){
        if(dis[u]==k)ans++;
        for(int i=0;i<G[u].size();i++){
            Edge &e=edges[G[u][i]];
            if(dis[u]<k&&dis[u]+e.cost>k&&(dis[e.v]>k||k<=e.cost-(k-dis[u])+dis[e.v])){
                ans++;
                if(k==e.cost-k+dis[u]+dis[e.v])cnt++;
            }
        }
    }
    printf("%d\n",ans-cnt/2);
    return 0;
}
/*
3 3 1
1 2 2
2 3 3
1 3 4
4
*/

題目大意:

給定一個01數組,現在支持兩種操作

1.將整個區間01翻轉

2.詢問整個大區間的最長不遞減子序列長度。

思路:

經典線段樹維護最長遞增子序列,考爛的題目,然而沒有時間看。。。

線段樹維護左邊區間開頭0的個數,右邊區間開頭0的個數,區間0的個數與1的個數。

然後只需要考慮合併時的貢獻,可以參考一下HDU6404這個題,把高低看成0和1,就是這個題了,合併很簡單的。

#include<bits/stdc++.h>
using namespace std;
#define all(a) a.begin(),a.end()

int n,m;
const int maxn=1e5+10;
int a[maxn];
struct node{
	int l,r;
	int r0=0,l0=0,a1=0,a0=0;
	int lazy=0;
}t[maxn<<2];
void build(int u,int l,int r){
	t[u].l=l,t[u].r=r;
	if(l==r){
		t[u].l0=t[u].r0=1;
		if(a[l]==1){
			t[u].a1=1;
			t[u].a0=0;
		}
		else {
			t[u].a1=0;
			t[u].a0=1;
		}
		return;
	}
	int mid=(l+r)/2;
	build(u<<1,l,mid);
	build(u<<1|1,mid+1,r);
	t[u].l0=max(t[u<<1].a0+t[u<<1|1].l0,t[u<<1].l0+t[u<<1|1].a1);
	t[u].a0=t[u<<1].a0+t[u<<1|1].a0;

	t[u].r0=max(t[u<<1|1].a0+t[u<<1].r0,t[u<<1|1].r0+t[u<<1].a1);
	t[u].a1=t[u<<1|1].a1+t[u<<1].a1;
}
int solve(){
	cout<<max(t[1].l0,max(t[1].a1,t[1].a0))<<endl;
	return 0;
}
void upd(int u){
	t[u<<1].lazy=!t[u<<1].lazy;
	t[u<<1|1].lazy=!t[u<<1|1].lazy;
	swap(t[u<<1].l0,t[u<<1].r0);
	swap(t[u<<1].a0,t[u<<1].a1);
	swap(t[u<<1|1].l0,t[u<<1|1].r0);
	swap(t[u<<1|1].a0,t[u<<1|1].a1);
}
void upd(int u,int L,int R){
	int l=t[u].l,r=t[u].r;
	if(l==L&&r==R){
		t[u].lazy=!t[u].lazy;
		swap(t[u].l0,t[u].r0);
		swap(t[u].a0,t[u].a1);
		return;
	}
	if(t[u].lazy){
		t[u].lazy=0;
		upd(u);
	}
	int mid=(l+r)/2;
	if(R<=mid)upd(u<<1,L,R);
	else if(L>mid)upd(u<<1|1,L,R);
	else upd(u<<1,L,mid),upd(u<<1|1,mid+1,R);
	t[u].l0=max(t[u<<1].a0+t[u<<1|1].l0,t[u<<1].l0+t[u<<1|1].a1);
	t[u].a0=t[u<<1].a0+t[u<<1|1].a0;

	t[u].r0=max(t[u<<1|1].a0+t[u<<1].r0,t[u<<1|1].r0+t[u<<1].a1);
	t[u].a1=t[u<<1|1].a1+t[u<<1].a1;
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cin>>n>>m;
	for(int i=1;i<=n;++i){
		char tmp;
		cin>>tmp;
		a[i]=tmp-'0';
	}
	build(1,1,n);
	while(m--){
		char q;
		cin>>q;
		if(q=='q')solve();
		else{
			int l,r;
			cin>>l>>r;
			upd(1,l,r);
		}
	}
	return 0;
}
/*
5 5
10011
q
c 1 5
q
c 1 3
q
*/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章