D:小A的线段(dfs)
蒟蒻赛时写的dfs超时了,以此记录一下自己错误的思路>>
可以看到本题m的数据范围在10以内,所以我们可以通过dfs来枚举出所有线段的组合情况,而要判断我们选择的线段是否能将所有的点覆盖至少两次.可以通过差分数组求前缀来判断..那么是否会超时呢?我们知道深搜时间复杂度是2^n(2种状态,最大深度为10),10个线段就是1024,然后判断数组需要O(n),也就是10的五次方,O(m*n) = 1024 * 10 ^ 5不超1e9 可以接受.
思路:
对于每一条线段,我们有选或者不选两种状态,那么设置一个use数组判断这个线段选了没有.然后通过构造差分数组来对左右端点操作.
代码:
/* */
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f;
const int MAX = 1e5+7;
int n,m,ans,l[15],r[15],c[MAX];
int use[15];
void dfs(int now)
{
if(now == m+1)
{
//如果m条线段选完了
memset(c,0,sizeof c);//差分初始化
for(int i=1;i<=m;i++)
{
if(use[i])
{
//观察他的状态
c[l[i]]++;
c[r[i]+1]--;
}
}
int flag = 1;
for(int i=1;i<=n;i++)
{
c[i]+=c[i-1];
if(c[i] < 2)flag = 0;
}
if(flag)ans++;//全都符合
return;
}
/*-重难点-*/
//在可以枚举所有可能的情况下 一个一个来 毕竟深搜就是要搜出所有可能的情况,所以每一个点都要把所有情况包含在内
for(int i=0;i<=1;i++)
{
//0表示不选 1表示选 -- 两种可能的状态
use[now] = i;
dfs(now+1);
use[now] = 0;
}
}
void solve()
/*算数开ll 存图用int*/
{
cin>>n>>m;
for(int i=1;i<=m;i++)
cin>>l[i]>>r[i];
dfs(1);//从第一个开始搜
cout<<ans;
}/*算数开ll 存图用int*/
int main()
{
ios::sync_with_stdio(false);cin.tie(0);
cout.tie(0);
//cout<<fixed<<setprecision(2);
int t=1;
//cin>>t;
while(t--)
solve();
return 0;
}
下次对状态的判断不能错了┭┮﹏┭┮
E:小A的任务(枚举 + 优先队列)
题目摘要:A的任务占一排,B的任务占一排,如果要完成某个B任务,那么需要先完成与之对应的A任务。现在要完成一定数量的B任务,求最小的工作量。
分析:目的是完成k个B任务,所以最少是在完成k个A任务的情况下完成才有k个B任务去让你完成,然而我们可以多完成一些A任务,然后在所以可以完成的B任务里面挑选k个最小的,所以本体思路就来了:枚举完成的A任务的任务数量,(可以在完成k个A任务前提下完成k个B任务,完成(k+1)个A任务前提下完成k个B任务...)然后将b任务放在优先队列里,每次够k个的时候取一下最小值。
但是如果我的优先队列是小根堆,每次取最小值,那么当k很大时,我需要遍历队列取出来,会达到O(n2)的复杂度。那么怎么来简化它呢?
定义两个变量一个sum1记录A的累加,一个sum2记录B的累加,每次当我的队列里面的元素大于k的时候,我把里面最大的那个去掉,同时sum2 - 最大的那个元素。然后当队列元素个数size=k时,取一下最小值,这样就O(1)的遍历了所有队列可能。
代码:
/* */
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
#define int long long
#define LL _int128
const int INF = 0x3f3f3f3f;
const int MAX = 1e6+7;
#define pb push_back
#define ff first
#define ss second
typedef pair<int,int>pai;
int a[MAX],b[MAX];
void solve()
/*算数开ll 存图改回int*/
{
int n,k;cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>b[i];
int x;
while(k--){
cin>>x;
int ans = 1e18;//注意开long long
int sum1=0,sum2=0;
priority_queue<int,vector<int>,less<int>>q;//大根堆
for(int i=1;i<=n;i++){
sum1+=a[i];
sum2+=b[i];
q.push(b[i]);
if(q.size() > x){
//现在把最大的那个(最不优的解)抛去
sum2 -= q.top();
q.pop();
}
if(q.size() == x){
//sum2是一组解
ans = min(ans,sum1+sum2);
}
}
cout<<ans<<endl;
}
}/*算数开ll 存图改回int*/
signed main()
{
ios::sync_with_stdio(false);cin.tie(0);
cout.tie(0);
//cout<<fixed<<setprecision(2);
int t=1;
//cin>>t;
while(t--)
solve();
return 0;
}