ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

5.6 NOI模拟

2022-05-07 21:05:29  阅读:192  来源: 互联网

标签:opt NOI 5.6 int res ite dep 模拟 mod


\(5.6\ NOI\)模拟

明天就母亲节了,给家里打了个电话(\(lj\ hsez\)断我电话的电,在宿舍打不了,只能用教练手机打了)

其实我不是很能看到自己的\(future,\)甚至看不到高三的希望,当然我不清楚我会被分到什么班(主要是停课前有几次考试考的很炸,最后一次才回到巅峰时期的一半,巅峰时期年级\(rk20-...\))

毕竟\(whk\)将近一年没学了(中间间歇性补了几次课),倒也能跟得上,但是也知道要真考试啥也不是,高三要分到一个氛围好的班级也很重要(啊喂,现在还没回高三,在这\(bb\)啥,现在这一阵子也是一直被这件事困扰了好长时间)

说实话,最差的结果也不是不能接受,毕竟选择都是自己选的,已经过去的再纠结也没用意义,困扰再久也没什么能解决的,但是最重要的是,把眼前的事情做好,一切结果就不会太差

家长说的是,珍惜好两个月,努力做好就好了(毕竟家长也只能鼓励了,真正要做事的还是自己)

不丧了,努力做好每一天就好了,现在想再多也改变不了过去,预测不了未来

而且,对于停课一年回归之后裸分\(T/P\)我还是有信心的(信心最重要了)

\(T1\)

尺取\(+\)正难则反\(+\)容斥

#include<bits/stdc++.h>
#define int long long
#define MAXN 2000005
using namespace std;
const int mod=1000000007;
int n,L,a[MAXN];
int res,res2,res3;
int my_pow(int a,int b)
{
	int res=1;
	while(b)
	{
		  if(b&1)
		  {
		  	 res=(res*a)%mod;
		  }
		  a=(a*a)%mod;
		  b>>=1;
	}
	return res;
}
signed main()
{
	scanf("%lld%lld",&n,&L);
	if(n<=3)
	{
	   cout<<0;
	   return 0;
	}
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
	}
	for(int i=1;i<=n;i++) a[i+n]=a[i]+L;
	for(int i=2;i<=n;i++)
	{
		if(2*(a[i]-a[i-1])>L)
		{
			cout<<0;
			return 0;
		}
	}
	if(2*(a[n]-a[1])<L)
	{
		cout<<0;
		return 0;
	}
	int ed=n,l=1,r=n;
	while(r>1&&2*(a[ed]-a[r-1])<L) r--;
	for(int i=1;i<=n;i++,ed++)
	{
	    while(l+1<=2*n&&2*(a[l+1]-a[i])<L) l++;
	    while(r<=ed&&2*(a[ed]-a[r])>=L) r++;
	    int len=l-i;
	    res+=my_pow(2,len);
	    res%=mod;
	    if(l>=r)
	    {
	    	res2+=my_pow(2,l-r+1)-(l-r+1);
	    	res2%=mod;
		    res3+=(l-r);
		}
		else res3++;
	}
	res++;
	res=(res*2-(res3+res2*2)+mod)%mod;
	cout<<(my_pow(2,n)-res+mod)%mod*my_pow(my_pow(2,n),mod-2)%mod;
}

\(T2\)

每次操作相当于

将牌分成若干堆,对每堆进行降序排列,并把奇数堆内部翻转

考虑分治操作,取一个\(mid\)

每次将小于\(mid\)的看成\(0,\)大于\(mid\)的看成\(1\)

\(Step_1:\)我们对于目前序列的操作应当是,把所有的\(0\)合并到一起,把所有的\(1\)合并到一起

\(Step_2:\)将\(0/1\)部分递归下去分别排序

可能存在左右操作数不同的情况,导致并不是完全有序,那么就进行操作有序拼接

\(sol_1\):

可以按照\(00/1000/100/1\)

change

具体的分配方式就是

从后往前扫,每一块的形式大概是\(0011/1100,\)然后如果最后一块是奇数块的话就划分到倒数第二块里面(反正我想不出来,\(lyx\)就是聪明——来自校长的称赞)

操作上限\(\lfloor log(L+2) \rfloor\)

\(sol_2:\)

我们最后递归下去返回上来的可能是\(0011/1100,\)

也就是最后可能是\(3412/4312\)这样的形式

还是说,我们分治的过程是怎么保证整体序列的\(?\)

显然我们可以通过一些操作使得部分发生变化,只改变另外部分的相对顺序(我们在分组的时候保证了分偶数组)

那么就比较好说了,代码。。。

#include<bits/stdc++.h>
using namespace std;
int n,D,dat[100010];
bool cpy[100010];
vector<int>opt[200];
int wkot(int l,int r,int dep)
{
    //开始分治,并记录深度,记录深度是为了同步 
    if(l==r)return dep;
    int md=l+r>>1;
    for(int i=l;i<=r;i++)
    {
        if(dat[i]<=md)
        {
            cpy[i]=false;
        }
        else
        {
            cpy[i]=true;
        }
        //小的赋值为0,大的赋值为1 
    }
    while(true)
    {
        //SOL1的操作过程 
        int fr;
        for(fr=l;fr<=md;fr++)
        {
            if(cpy[fr])goto EB;
        }
        break;
        EB:
        dep++;
        //操作次数加一 
        for(int i=r;i>=fr;)
        {
            opt[dep].push_back(i);
            //放入操作的端点 
            while(i>=fr&&cpy[i]==cpy[r])i--;
            while(i>=fr&&cpy[i]!=cpy[r])i--;
        }
        if(opt[dep].size()&1)
        {
            opt[dep].push_back(fr-1);
            //为了保证操作块数始终为偶数
            //考虑是否把最后一段单独提出来 
        }
        fr=l;int op=0;
        for(vector<int>::reverse_iterator ite=opt[dep].rbegin();ite!=opt[dep].rend();ite++)
        {
            //简单操作,把代换序列和原序列全部翻转
            if(*ite<l)break;//这个我没看见... 
            if(op)
            {
                reverse(cpy+fr,cpy+*ite+1);
                reverse(dat+fr,dat+*ite+1);
            }
            op^=1;fr=*ite+1;
        }
    }
    if(dat[md+1]!=md+1)
    {
        //把mid+1放到右边块的最左边 
        if(dat[r]==md+1)
        {
            //在下一层先把他放在最小值的位置 
            opt[++dep].push_back(md);
            opt[dep].push_back(r);
            reverse(dat+md+1,dat+r+1);
        }
        else if(dat[r-1]==md+1)
        {
            //先交换最右边两个
            //后交换前面 
            opt[++dep].push_back(r-2);
            opt[dep].push_back(r);
            swap(dat[r],dat[r-1]);
            opt[++dep].push_back(md);
            opt[dep].push_back(r);
            reverse(dat+md+1,dat+r+1);
        }
        else
        {
            for(int i=md+1;i<=r;i++)
            {
                if(dat[i]==md+1)
                {
                    opt[++dep].push_back(md);
                    opt[dep].push_back(i);
                    opt[dep].push_back(r-1);
                    opt[dep].push_back(r);
                    reverse(dat+md+1,dat+i+1);
                    break;
                }
            }
        }
    }
    int lr=wkot(l,md,dep),rr=wkot(md+1,r,dep);
    if(lr<rr)
    {
        //深度不同的话,就搞成相同的,在每个操作里面都塞一个不影响状态的左边任意翻转就好了 
        for(int i=lr+1;i<=rr;i++)
        {
            opt[i].push_back(md-1);
            opt[i].push_back(md);
        }
    }
    else if(rr<lr)
    {
        //显然同理 
        for(int i=rr+1;i<=lr;i++)
        {
            opt[i].push_back(r-1);
            opt[i].push_back(r);
        }
    }
    return max(lr,rr);
}
int main()
{
    scanf("%d%d",&n,&D);
    for(int i=1;i<=n;i++)
    {
        cin>>dat[i]; 
    }
    int org;
    for(org=2;org<=n;org++)
    {
        if(dat[org]==1)
        {
            reverse(dat+org,dat+n+1);
            reverse(dat+1,dat+n+1);
            //先把1,整到最左边 
            break;
        }
    }
    int cn=wkot(1,n,0);
    if(cn&1)
    {
        cn++;
        for(int i=1;i<=n;i++)
        {
            opt[cn].push_back(i);
        }
    }
    if(org<=n)
    {
        cn++;
        printf("%d\n2 %d %d\n",cn,org-1,n-org+1);
        cn--;
    }
    else
    {
        printf("%d\n",cn);
    }
    for(int i=1;i<=cn;i++)
    {
        sort(opt[i].begin(),opt[i].end());
        if(i&1)
        {
            int lst=0;
            printf("%d ",(int)opt[i].size());
            for(vector<int>::iterator ite=opt[i].begin();ite!=opt[i].end();ite++)
            {
                printf("%d ",*ite-lst);
                lst=*ite;
            }
        }
        else
        {
            if(opt[i].size()<n)
            {
                printf("%d 0 ",(int)opt[i].size()+1);
                //除了特殊情况,其余都提前塞一个0
                //分奇偶整呗...考虑塞0或者不塞 
            }
            else
            {
                printf("%d ",(int)opt[i].size());
            }
            for(vector<int>::reverse_iterator it=opt[i].rbegin(),ite=it+1;ite!=opt[i].rend();it=ite,ite++)
            {
                printf("%d ",*it-*ite);
            }
            printf("%d ",opt[i].front());
        }
        cout<<endl;
    }
    return 0;
}

\(T3\)

不会

标签:opt,NOI,5.6,int,res,ite,dep,模拟,mod
来源: https://www.cnblogs.com/Eternal-Battle/p/16244085.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有