ICode9

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

6.19 NOI 模拟

2022-06-19 19:34:09  阅读:129  来源: 互联网

标签:6.19 ch poz NOI int MAXN ey 模拟 define


发现 \(Typro\) 没保存的草稿也是可以找回的,\(tql\)

\(T1\ bs\)

考虑选的必然是开头的连续一段,那么直接二分\(+\)判定即可

由于数据范围是\(5\times 10^7\),需要优秀的常数,毕竟正解是线性的。

#define Eternal_Battle ZXK
#include<bits/stdc++.h>
#define MAXN 50000005
using namespace std;
const int INF=INT_MAX;
int a[MAXN],c[MAXN],x[MAXN],y[MAXN],z[MAXN],Ans=INF,n,m,k;
bool vis[MAXN];
#define FastIO
#ifdef FastIO
    char buf[1<<21],*p1,*p2;
    #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif
template<class T>
T Read()
{
    T x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
        f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<1)+(x<<3)+(ch^'0');
        ch=getchar();
    }
    return x*f;
}
int (*read)()=Read<int>;
#define read Read<int>
inline bool check(int x)
{
    int res=0,cnt=0;
    for(int i=1;i<=n;i++)
    {
        if(i<=x) res++;
        else if(res>=a[i]) res++;
        if(i<=x) cnt+=(a[i]>(i-1)); 
    }
    if(res>=m)
    {
       Ans=min(Ans,cnt);
       return true;
    }
    return false;
}
void create()
{
    for(int i=1;i<=k;i++) c[i]=read(),x[i]=read(),y[i]=read(),z[i]=read();
    int cnt=1;
    for(int i=1;i<=k;i++)
    {
        for(int j=cnt+1;j<=cnt+c[i];j++)
        {
            a[j]=1ll*(1ll*x[i]*a[j-1]+y[i])%z[i];
        }
        cnt+=c[i];
    }
}
void solve()
{
    int l=0,r=n,mid;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if(check(mid)) r=mid-1;
        else l=mid+1;
    }
    cout<<Ans<<"\n";
}
signed main()
{
    scanf("%d%d",&n,&m);
    scanf("%d%d",&a[1],&k);
    create();
    solve();
}

\(T2\ dp\)

比较简单的递推转通项公式:

\[f_n=\frac{(\frac{a+\sqrt{a^2+4b}}{2})^n-(\frac{a-\sqrt{a^2+4b}}{2})^n}{\sqrt{a^2+4b}} \]

\[A=\frac{a+\sqrt{a^2+4b}}{2} \\ B=\frac{a-\sqrt{a^2+4b}}{2} \]

\(Sit_1:\)

\[a^2+4b=0 \\ f_n=\frac{a}{2}f_{n-1}+(\frac{a}{2})^{n-1} \\ f_n=n\times (\frac{a}{2})^{n-1} \\ f_i=x,f_{i+1}=y \\ \left\{ \begin{aligned} i\times &A^{i-1}=x \\ (i+1)&\times A^{i}=y \end{aligned} \right. \\ y-Ax=A^i \]

首先我们可以轻松得到 \(i\) 在\(\mod p-1\)的解,但是我们还要保证两个都要满足,所有我们需要得到在\(\mod p\times (p-1)\)下的最小解

\(Sit_2:\)

\[a^2+4b\ne 0 \\ AB=b \]

考虑如果有二次剩余的话,就会出现\(O(p)\)的循环,证明的话可用费马小定理。

我们\(O(p)\)必然会出现一个 \(0\),但是我们下一个位置可能不是 \(1\),如果是 \(k\)

那么我们设当前 \(0\) 的位置是 \(T\) ,\([T,2)\) 就是 \([0,T)\) 的 \(k\) 倍,我们只需要得到 \(f_i/f_{i+1}=x/y\) 的位置然后一直乘 \(k\) 就好了

#define Eternal_Battle ZXK
#include<bits/stdc++.h>
#define ull unsigned long long
#define int long long
using namespace std;
//#define FastIO
#ifdef FastIO
    char buf[1<<21],*p1,*p2;
    #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif
template<class T>
T Read()
{
    T x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
        f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<1)+(x<<3)+(ch^'0');
        ch=getchar();
    }
    return x*f;
}
int (*read)()=Read<int>;
#define read Read<int>
int mod,a,b,q;
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;
}
int Inv(int x)
{
    return my_pow(x,mod-2);
}
int inv[10000005],pA[10000005],fib[10000005];
void sub1()
{
    unordered_map<int,int>mp;
    int inv2=(mod+1)/2;
    inv[0]=inv[1]=1;
    for(int i=2;i<=mod;i++)
    {
        inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    }
    int A=a*inv2%mod;
    int jie=mod-1;
    pA[0]=1;
    for(int i=1;i<=mod;i++)
    {
        pA[i]=(pA[i-1]*A)%mod;
    }
    for(int i=0;i<=mod;i++)
    {
        if(!mp[pA[i]])  mp[pA[i]]=i;
        else mp[pA[i]]=min(mp[pA[i]],i),jie=min(jie,i-mp[pA[i]]);
    }
    scanf("%lld",&q);
    for(int i=1,x,y;i<=q;i++)
    {
        x=read();y=read();
        if(x==0&&y==1)
        {
            cout<<0<<"\n";
            continue;
        }
        int res=(y+mod-A*x%mod)%mod;
        int now1=mp[res];//mod jie
        if(!mp[res])
        {
            cout<<-1<<"\n";
            continue;
        }
        int now2=(x*inv[pA[now1-1]])%mod;//mod p
        int a=now1;
        int Ans=(ull)((1ull-mod+1ull*(mod*jie))%(mod*jie)*now2%(mod*jie)+mod*now1)%(mod*jie);
        cout<<Ans<<"\n";
    }
}
void sub2()
{
    unordered_map<int,int>mp;
    int jump[1000005];
    inv[0]=inv[1]=1;
    for(int i=2;i<=mod;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    fib[0]=0,fib[1]=1;
    int jie=0,k;
    for(int i=2;;i++)
    {
        fib[i]=(a*fib[i-1]+b*fib[i-2])%mod;
        if(fib[i-1]==0) 
        {
            k=fib[i];
            jie=i-1;
            break;
        }
        mp[fib[i]*inv[fib[i-1]]%mod]=i;
    }
    int jk=1;
    memset(jump,-1,sizeof(jump));
    for(int i=0;i<=mod;i++)
    {
        if(jump[jk]!=-1) jump[jk]=min(jump[jk],i);
        else jump[jk]=i;
        (jk*=k)%=mod;
    }
    jump[1]=0;
    scanf("%lld",&q);
    for(int i=1,x,y;i<=q;i++)
    {
        scanf("%lld%lld",&x,&y);
        int res=y*inv[x]%mod;
        int now1=fib[mp[res]];
        int poz=mp[res];
        int jp=y*inv[now1]%mod;
        int mul=jump[jp];
        if(jump[jp]==-1||!mp[res])
        {
        	cout<<-1<<"\n";
        	continue;
		}
        poz+=mul*jie;
        cout<<poz-1<<"\n";
    }
}
signed main()
{
    scanf("%lld%lld%lld",&mod,&a,&b);
    int det=(a*a%mod+4*b%mod)%mod;
    if(det==0) sub1();
    else sub2();
}

\(T3\ dis\)

首先翻转坐标系保证 \(s_x\leq e_x\),\(s_y \leq e_y\)

一个没有证明的结论:

一定存在一条 \(x\) 轴不降或 \(y\) 轴不降的最优路径

\(RU\) 路径为优先向右路径,\(RD.LU,LD\)同理

\(RU/RD\) 路径圈定了一个区域

同理 \(RU/RD\) 也圈定了一条区域

如果终点不在区域内,那么一定在 \(RU/ UR\) 区域的中间位置,那么从终点开始的 \(LD\) 路径必然只会和其中之一相交,拼接起来即为答案起点和终点的曼哈顿距离,形象的说就是这条路上没有任何障碍。

如果在区域内的我们可以简单地进行扫描线更新一下最短路了。

\(31pts\) 复杂度错了的代码

#define Eternal_Battle ZXK
#include<bits/stdc++.h>
#define int long long
#define MAXN 2500005
using namespace std;
#define FastIO
#ifdef FastIO
	char buf[1<<21],*p1,*p2;
	#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif

template<class T>
T Read()
{
	T x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')
		f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}
int (*read)()=Read<int>;
#define read Read<int>
struct node
{
    int opt,x1,y1,x2,y2;
}poz[MAXN];
struct gph
{
    int dis,y;
};
int n,sx,sy,ex,ey,Fin=INT_MAX;
bool cmp(node a,node b)
{
    return a.x1<b.x1;
}
void sol()
{
    int b[MAXN],bc[MAXN],Ans=INT_MAX,cnt,tot;
    int Maxx=-INT_MAX,Minx=INT_MAX;
    set<pair<int,int> >line[MAXN];
    map<int,int>mp;
    for(int i=1;i<=n;i++)
    {
        if(sx>poz[i].x1&&sx<poz[i].x2) Maxx=max(Maxx,poz[i].x2);
        if(ex>poz[i].x1&&ex<poz[i].x2) Minx=min(Minx,poz[i].x1);
    }
    if(Maxx>Minx)
    {
       return ;
    }
    for(int i=1;i<=n;i++)
    {
        b[++cnt]=poz[i].x1;
        b[++cnt]=poz[i].x2;
    }
    b[++cnt]=ex;
    sort(b+1,b+1+cnt);
    for(int i=1;i<=cnt;i++) if(!mp[b[i]]) mp[b[i]]=++tot,bc[tot]=b[i];
    for(int i=1;i<=n;i++)
    {
        line[mp[poz[i].x1]].insert(make_pair(poz[i].y2,poz[i].y1));
        line[mp[poz[i].x2]].insert(make_pair(poz[i].y2,poz[i].y1));
    }
    line[mp[ex]].insert(make_pair(ey,ey));
    vector<gph>Sit;
    Sit.push_back((gph){0,sy});
    for(int i=1;i<=tot;i++)
    {
        if(bc[i]<sx||bc[i]>ex) continue;
        vector<gph>zy;
//      	cout<<"x: "<<bc[i]<<"\n";
        for(int j=0;j<Sit.size();j++)
        {
            int poz=Sit[j].y;
            int dis=Sit[j].dis;
//          cout<<Sit[j].y<<"\n";
            set<pair<int,int> >::iterator it=line[i].lower_bound(make_pair(poz,poz));
            if(it->second>=poz||it==line[i].end())
            {
//             cout<<"ps: "<<bc[i]<<" "<<it->first<<" "<<poz<<"\n";
               if(bc[i]==ex&&poz==ey) Ans=min(Ans,dis);
               zy.push_back((gph){dis,poz});
            }
//          cout<<"siz: "<<line[i].size()<<"\n";
            for(it=line[i].begin();it!=line[i].end();it++)
            {
                int y1=it->first;
                int y2=it->second;
                zy.push_back((gph){dis+abs(y1-poz),y1});
                zy.push_back((gph){dis+abs(y2-poz),y2});
                if(bc[i]==ex&&y1==ey)
                {
                   Ans=min(Ans,dis+abs(y1-poz));
                }
                if(bc[i]==ex&&y2==ey)
                {
                   Ans=min(Ans,dis+abs(y2-poz));
                }
            }
        }
        map<int,bool>vis;
        vis.clear();
        Sit.clear();
        unordered_map<int,int>Mid;
//        set<pair<int,int> >Mid;
        while(zy.size())
		{
			int y=zy.back().y;
			if(!Mid[y])Mid[y]=zy.back().dis;
			else Mid[y]=min(Mid[y],zy.back().dis);
			zy.pop_back();
		} 
		for(unordered_map<int,int>::iterator it=Mid.begin();it!=Mid.end();it++)
		{
			Sit.push_back((gph){it->second,it->first});
		}
    }
    Fin=min(Fin,Ans+abs(sx-ex));
}
signed main()
{
//  	freopen("ex_data4.in","r",stdin);
//  freopen("ex_data3.in","r",stdout);
    scanf("%lld%lld%lld%lld%lld",&n,&sx,&sy,&ex,&ey);
    for(int i=1;i<=n;i++)
    {
    	poz[i].x1=read();
    	poz[i].y1=read();
    	poz[i].x2=read();
    	poz[i].y2=read();
        if(sx>ex) poz[i].x1*=-1,poz[i].x2*=-1;
        if(sy>ey) poz[i].y1*=-1,poz[i].y2*=-1;
        if(poz[i].x1>poz[i].x2) swap(poz[i].x1,poz[i].x2);
        if(poz[i].y1>poz[i].y2) swap(poz[i].y1,poz[i].y2);
    }
    if(sx>ex) sx*=-1,ex*=-1;
    if(sy>ey) sy*=-1,ey*=-1;
    sol();
    for(int i=1;i<=n;i++)
    {
        swap(poz[i].x1,poz[i].y1);
        swap(poz[i].x2,poz[i].y2);
    }
	swap(sx,sy); swap(ex,ey);
    sol();
    cout<<Fin<<"\n";
}

我们需要把枚举转移点改成,枚举需要删的点去转移,大概就是维护一个\(set\),每次先把需要删的删去,然后只需要用中间一部分更新即可

#include<bits/stdc++.h>
#define MAXN 250010
#define int long long 
using namespace std;
const int INF=1e9;
int n,ans=1e18,sx,sy,ex,ey;
int a[MAXN],b[MAXN],c[MAXN],d[MAXN];
pair<pair<int,int>,int > t[MAXN];
struct io
{
    int len,x,y;
    friend bool operator <(io a,io b)
    {
        return a.y<b.y;
    }
}tmp;
set<io> se;
set<io>::iterator it,itt;
void work()
{
    se.clear();
    se.insert(io{0,sx,sy});
    for(int i=1;i<=n;++i) t[i]=make_pair(make_pair(a[i],b[i]),d[i]);
    sort(t+1,t+n+1);
    for(int i=1;i<=n;++i)
    {
        int s=t[i].first.first,U=INF,D=INF,l=t[i].first.second,r=t[i].second;
        if(s>=sx&&s<=ex)
        {
            auto it=se.lower_bound(io{0,0,l});
            while(it!=se.end()&&(*it).y<=r)
            {
                tmp=*it,itt=it,++it,se.erase(itt);
                U=min(U,tmp.len+s-tmp.x-tmp.y+r),D=min(D,tmp.len+s-tmp.x+tmp.y-l);
            }
            (U<INF)&&(se.insert(io{U,s,r}),0),(D<INF)&&(se.insert(io{D,s,l}),0);
        }
    }
    auto it=--se.end();
    if(it->y<ey) return;
    for(it=se.begin();it!=se.end();++it) ans=min(ans,it->len+ex-it->x+abs(ey-it->y));
}
void init()
{
    if(sx>ex) swap(sx,ex),swap(sy,ey);
    if(sy>ey)
    {
        sy=INF-sy,ey=INF-ey;
        for(int i=1;i<=n;++i) swap(b[i],d[i]),b[i]=INF-b[i],d[i]=INF-d[i];
    }
}
void swpall()
{
    swap(sx,sy),swap(ex,ey);
    for(int i=1;i<=n;++i) swap(a[i],b[i]),swap(c[i],d[i]);
}
signed main()
{
    scanf("%lld %lld %lld %lld %lld",&n,&sx,&sy,&ex,&ey);
    for(int i=1;i<=n;++i) scanf("%lld %lld %lld %lld",&a[i],&b[i],&c[i],&d[i]);
    init(),work();
    swpall(),work();
    if(ans==1e18) ans=ex+ey-sx-sy;
    cout<<ans<<endl;
}

标签:6.19,ch,poz,NOI,int,MAXN,ey,模拟,define
来源: https://www.cnblogs.com/Eternal-Battle/p/16391145.html

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

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

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

ICode9版权所有