ARC 070

来源:互联网 发布:网站数据库抓取 编辑:程序博客网 时间:2024/06/06 09:19

C
因为可以原地不动,所以二分找到最小的1+2+….k>=n的k,可以从1~k中去掉多出的,k就是答案

D
dp前缀和后缀和,用bitset优化转移
对于每个数O(n)判前后缀能不能凑出n-x~n-1的数

E
multiset删一个值会把这个值的全部都删掉,所以要用指针指一下,然后删指针。

用f[i][x]表示前i个矩形合法,第i个矩形左端点在x的最小花费,有转移
f[i][x]=|xli|+f[i1][x](x(ri1li1)<=x<=x+rili)
将f[i]看作一个函数,发现他从左到右每个线段斜率递增,斜率依次为i1,i,.....0,1,..i+1
(如果没有斜率为k的,可以视他在k-1,k+1之间,长度为0)
斜率为0处是最低点

每次转移,相当于将他最低点向左右平移ri1li1,rili,然后加上一条折线,折线会增加两个坐标相同的拐点li,可以当作他们中间有一条斜率为0的线段,最后的答案就是最低点的高度。
考虑怎么维护这个东西,把折线从斜率=0的地方划开,用两个优先队列(或multiset)维护左右的点集,平移时给整个队列打个标记
每次加一次函数,若li在L~R,给左右队首加入L,R,若在某一边,在这边加入两个转角,将这边的top弹出,放入另一边的队列
斜率不用维护,因为斜率一定是-k,-k+1..0..k这样递增的,我们只关心斜率为0的地方,他在两个队列的队首中间,其他不用管

code:

#include<set>#include<map>#include<deque>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<bitset>#include<string>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<complex>#include<iostream>#include<algorithm>#define ll long long#define inf 1e10using namespace std;const int maxn = 210000;int n;multiset<ll>ql,qr;multiset<ll>::iterator it;ll addL,addR,len,re;int main(){    scanf("%d",&n);    for(int i=1,las=0;i<=n;i++,las=len)    {        ll l,r; scanf("%lld%lld",&l,&r);        len=r-l;        if(i==1)        {            ql.insert(-inf); ql.insert(l);            qr.insert(inf); qr.insert(l);            continue;        }        addL-=len,addR+=las;        ll pl=*ql.rbegin()+addL,pr=*qr.begin()+addR;        if(l<pl)        {            it=ql.end();it--; ql.erase(it);            ql.insert(l-addL); ql.insert(l-addL);            re+=pl-l;            qr.insert(pl-addR);        }        else if(l<=pr)            ql.insert(l-addL),qr.insert(l-addR);        else        {            it=qr.begin(); qr.erase(it);            qr.insert(l-addR); qr.insert(l-addR);            re+=l-pr;            ql.insert(pr-addL);        }    }    printf("%lld\n",re);    return 0;}

F
当A<=B时,因为B个不友好的人中的A个人可以表现的和诚实的A个人一样,所以无法判断哪些是诚实的人
否则,当我们询问p,回答q不诚实时,p和q中间一定有至少一个不诚实的人,将p,q一起去掉不影响
所以维护一个栈,每次从没问过的人中任选一人x,问栈顶的p,x是否诚实,若不诚实,同时丢掉,否则入栈,最后得到的栈从底至上stack0..k-1,其中至少有1个诚实的人,且每个人都说他上面的人诚实,所以栈顶的人一定是诚实的,再问他所有人是否诚实就行了

code:

#include<set>#include<map>#include<deque>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<bitset>#include<string>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<complex>#include<iostream>#include<algorithm>#define ll long longusing namespace std;const int maxn  = 4100;int n,A,B;int t[maxn],tp;char str[110];bool v[maxn];int main(){    //freopen("tmp.in","r",stdin);    //freopen("tmp.out","w",stdout);    cin>>A>>B; n=A+B;    if(A<=B) { cout<<"Impossible"<<endl; return 0; }    for(int i=0;i<n;i++)    {        if(!tp) t[++tp]=i;        else        {            cout<<"? "<<t[tp]<<" "<<i<<endl;            cin>>str;            if(str[0]=='N') tp--;            else t[++tp]=i;        }    }    int x=t[tp]; v[x]=true;    for(int i=0;i<n;i++) if(i!=x)    {        cout<<"? "<<x<<" "<<i<<endl;        cin>>str;        v[i]=str[0]=='Y'?true:false;    }    cout<<"! ";    for(int i=0;i<n;i++) cout<<(v[i]?1:0);    cout<<endl;    return 0;}
原创粉丝点击