ACM-思维-CF#521div3 B+C+D+E+ (ECR#53div2的C 二分答案)

#521div3
https://codeforces.com/contest/1077
#53div2-C
https://codeforces.com/contest/1073/problem/C
进入正文

521B
找到使得101不存在的最少改变序列。
就是离线处理这个序列,贪心的遇到101就改掉第二个1为0,然后一直On查找至结束

	int t;
    cin>>t;
    n=0;
    for(int i=0;i>sumx[i];
        if(i>1&&sumx[i]==1&&sumx[i-2]==1&&sumx[i-1]==0){
            n++;
            sumx[i]=0;
        }
    }
    cout<

521C
去掉某个序列中的值,可以使得剩下的序列中有一个值,等于,剩下序列和的一半。判断sum-a[i]是不是2的倍数,然后判断剩下的序列里存不存在(sum-a[i])/2。

ll n,m,x,y;
int sumx[maxm+5];
mapsumy;
vectorque;
int main(){
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    n=0;
    sumy.clear();
    for(int i=0;i>sumx[i];
        sumy[sumx[i]]++;
        n+=sumx[i];
    }
    que.clear();
    for(int i=0;i0){
            if(m==sumx[i]){
               if(sumy[m]>1)que.push_back(i+1);
            }
            else que.push_back(i+1);
        }
    }
    cout<

521D
我提出了个假算法,被hack了,见太少,不知道这个是二分。。。。
二分是对单调序列,这里是二分出符合条件的最大次数,然用这个次数去check,判断是否满足K个

#include
using namespace std;
#define ll unsigned long long
#define mem(a,b) memset(a,b,sizeof a)
const int mod=1e9+7;
const int maxn=2e5;//3个确定 1e15
int a[maxn+5],b[maxn+5];
ll n,k;
bool check(ll mid){
    int sum=0;
    for(int i=1;i<=maxn;i++){
        sum+=b[i]/mid;
    }
    return (sum>=k);
}
int main() {
    int t;
    cin>>n>>k;
    mem(b,0);
    for(int i=0;i>a[i];
       b[a[i]]++;
    }
    ll l=1,r=n;
    ll mid;
    ll temp,ans;
    while(l<=r){
        mid=(l+r)/2;
        if(check(mid)){
            ans=mid;
            l=mid+1;
        }
        else r=mid-1;
    }
    //cout<q;
    q.clear();
    ll sum=0;
    for(int i=1;i<=maxn;i++){
        while(b[i]>=ans&&sum

53C
和上面有关联的二分,所以在这里讲了
首先:|x|+|y|>n肯定不用考虑,因为一定不行
再者:|x|+|y|-n是奇数肯定不用考虑,因为多的路走了也回不去
最后:二分头尾差的长度,用长度去check能不能改变,条件依然是上面的判断

string s;
bool vis[maxn+5];
pair node0[maxn+5],node1[maxn+5];
int n;
bool check(int len){
    bool f=false;
    for(int i=0;i<=m-len;i++){
        ll rx=node1[i+len].first,ry=node1[i+len].second;//距离终点的距离   肯定的
        ll lx=node0[i].first,ly=node0[i].second;//从源点出发走的距离       肯定的
        ll cha=abs(rx-lx)+abs(ry-ly);
        if(len>=cha&&((len-cha)%2==0)){
            f=true;
            break;
        }
    }
    return f;
}
void solve(){
    ll x,y,xy;
	cin>>n;
	cin>>s;
	cin>>x>>y;
	xy=abs(x)+abs(y);
	if(xy>m)cout<<"-1\n";
    else if((m-xy)%2)cout<<"-1\n";
    else {
        ll a1=0,a0=0,b1=0,b0=0;
        mem(vis,0);
        node0[0]={0,0};
        for(int i=0;i=0;i--){
            if(s[i]=='L')node1[i]={node1[i+1].first+1,node1[i+1].second};
            if(s[i]=='R')node1[i]={node1[i+1].first-1,node1[i+1].second};
            if(s[i]=='D')node1[i]={node1[i+1].first,node1[i+1].second+1};
            if(s[i]=='U')node1[i]={node1[i+1].first,node1[i+1].second-1};
        }
        if(node0[m].first==x&&node0[m].second==y){
            cout<<"0\n";
            return;
        }
        int l=1,r=m+1,mid,ans=1;
        while(l<=r){
            mid=(l+r)/2;
            if(check(mid)){
                ans=mid;
                r=mid-1;
            }
            else l=mid+1;
        }
        cout<

521E
从已知序列,找个序列,符合后一位是前一位的两倍,其中这个序列的和最大。
看题解的:题目标号没有用,只需要处理次数,map统计一下,再存入vector,进行排序。从1枚举到最多的那个数量,判断能不能往前找到当前值的1/2。
注意:这里有2e5最多2^18,所以最多找18次,于是枚举完全没问题,同时,为了避免可能的局部最优,这里的枚举要求枚举到最大的次数往前,而不是最小的次数往后。 另外:这里的数列求最值,不符合单调的二分性质,所以二分可能会有问题,三分能过(某队友三分过的)。

ll n;
mapa;
void solve(){
	scanf("%d",&m);
	a.clear();
	for(int i=0;icnt;
	for(auto it:a)cnt.push_back(it.second);
	sort(cnt.begin(),cnt.end());
	n=cnt[0];
	int len=cnt.size()-1;
	ll ans=0;
	for(int i=1;i<=cnt[len];i++){
        int pos=len;
        ll cur=i;
        ll res=cur;
        while(cur%2==0&&pos>0){
            cur/=2;
            pos--;
            if(cnt[pos]

难得的div3场,但是我被hack了。。。真惨

你可能感兴趣的:(算法题解)