Loading

noip模拟12

A. 简单的区间(Interval)

太菜..只能打线段树把 O(n^3) 优化成 O(n^2 * logn)..

我这里根据题解进行了 STL 优化(其实是 pyt 大佬的想法..)

我们这里可以类比曾经做过的《将军令》,如果某两段的前缀模 k 的余数相同,那么就以为着 ta 们的差分数组一定是可以被 k 整除的..

然后使用 Vector 优化即可..

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define lf double
#define mp make_pair
const ll N=3e5+50;
const ll MOD=1e6+50;
inline void read(ll &ss)
{
    ss=0; bool cit=0; char ch;
    while(!isdigit(ch=getchar())) if(ch=='-') cit=1;
    while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
    if(cit) ss=-ss;
}
ll n,m,sum,mod;
ll val[N],pre[N];
ll l[N],r[N];
vector<ll> vec[MOD];
deque<ll> que;
signed main()
{
    read(n); read(mod);
    vec[0].push_back(0);
    for(ll i=1;i<=n;i++)
    {
        read(val[i]);
        pre[i]=(pre[i-1]+val[i])%mod;
        vec[pre[i]].push_back(i);
    }
    ll head,temp; l[1]=1;
    for(ll i=1;i<=n;i++)
    {
        if(que.empty())
        {
            que.push_back(i);
        }
        else
        {
            if(val[que.front()]<val[i])
            {
                head=que.front(); temp;
                while(que.size() and val[que.front()]<val[i])
                {
                    temp=que.front(); que.pop_front();
                    r[temp]=head; l[i]=l[temp]; 
                }
                que.push_front(i);
            }
            else             
            {
                que.push_front(i);
                l[i]=i;
            }
        }
    }
    head=que.front();
    while(que.size())
    {    
        temp=que.front(); que.pop_front();
        r[temp]=head;
    }
    ll ans=0; ll ls,rs;
    #define lb lower_bound
    #define ub upper_bound
    for(ll i=1;i<=n;i++)
    {
        if(r[i]-i<=i-l[i])
        {
            for(ll j=i;j<=r[i];j++)
            {
                temp=(pre[j]-val[i]%mod+mod)%mod; //cout<<temp<<" "<<l[i]<<" "<<i<<" ";
                ls=lb(vec[temp].begin(),vec[temp].end(),l[i]-1)-vec[temp].begin();
                rs=lb(vec[temp].begin(),vec[temp].end(),i)-vec[temp].begin();
                ans+=(rs-ls); //cout<<rs<<" "<<ls<<endl;
            }
        }
        else
        {
            for(ll j=l[i];j<=i;j++)
            {
                temp=(pre[j-1]+val[i])%mod; //cout<<temp<<" "<<r[i]<<" "<<i<<" ";
                ls=lb(vec[temp].begin(),vec[temp].end(),i)-vec[temp].begin();
                rs=lb(vec[temp].begin(),vec[temp].end(),r[i]+1)-vec[temp].begin();
                ans+=(rs-ls); //cout<<rs<<" "<<ls<<endl;
            }
        }
    }
    printf("%lld",ans-n);
    return 0;
}
A_Code

 

B. 简单的玄学(Random)

本以为这是一道简单的数学题,没想到 ta 竟然真的是一道简单的数学题..(但是直接 WA 成了 10 分)

按着自己的思路打..发现自己和正解的思路差了一个约分,最后突然发现了一个显然的东西:

m 和 n 的最大公约数不一定等于 m%p 和 n%p 的最大公约数..然而我直接在一顿模完之后搞了个辗转相除..

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define lf double
#define mp make_pair
const ll mod=1e6+3;
inline void read(ll &ss)
{
    ss=0; bool cit=0; char ch;
    while(!isdigit(ch=getchar())) if(ch=='-') cit=1;
    while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
    if(cit) ss=-ss;
}
ll n,m;
ll ksm(ll a,ll b,ll c)
{
    ll temp=1; a%=c;
    while(b)
    {
        if(b&1) temp=(temp*a)%c;
        a=(a*a)%c; b>>=1;
    }
    return temp%c;
}
inline ll get2(ll x)
{
    ll res=0;
    while(x)
    {
        res+=(x>>1);
        x>>=1;
    }    
    return res;
}
signed main()
{
    read(n); read(m);
    ll gg=0,ff=1;
    ll a=m%mod,b=m/mod,c=n%(mod-1);
    gg=get2(m-1);
    ff=n%(mod-1); ff=ff*(m%(mod-1))%(mod-1);
    ff=((ff-gg+mod-1)%(mod-1)-c+(mod-1)*(mod-1))%(mod-1);
    ll x=ksm(2,(n+mod-1)%(mod-1),mod);  ll y=ksm(2,ff,mod);
//    ll ans=1;   ll x=1,y=1;
    ll ans=ksm(2,(gg+n)%(mod-1),mod); ans=ksm(ans+mod,mod-2,mod);
    for(ll i=0;i<=a-1;i++) ans=(ans*ksm(x-i+mod,(b+1)%(mod-1),mod))%mod;
    for(ll i=a;i<=mod-1;i++) ans=(ans*ksm(x-i+mod,b%(mod-1),mod))%mod;
    ans=(y-ans+mod)%mod;  
    printf("%lld %lld",ans,y);
    return 0;
}
/*
16514896165186541 89678946198484
*/
B_Code

 

C. 简单的填数(Req)

个人认为这是一个我从未接触过的思想..(可能是因为我太菜..)

定义两个二元组 ( up 和 down ),然后分别记录两个极端的决策..

并且这两个二元组并非毫无干系,up 记录最优决策,与此同时 up 与 down 一起进行是否存在解的判定..

考后一开始打了一个不是数组的 up 和 down ,最后发现不能记录最后的输出结果..所以最后选择了给 up 和 down 分别赋一个数组同时记录最后的输出合法解..(其实只记录 up 就可以,毕竟只有 up 记录最优解..|| 如果你看不懂这句话.那就跳过去叭..)

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define lf double
#define mp make_pair
const ll N=2e6+50;
inline void read(ll &ss)
{
    ss=0; bool cit=0; char ch;
    while(!isdigit(ch=getchar())) if(ch=='-') cit=1;
    while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
    if(cit) ss=-ss;
}
ll n,m;
ll val[N],w[N],vis[N];
pair<ll,ll> up[N],down[N]; // 数为 x, 数量为 y
signed main()
{
    read(n);
    for(ll i=1;i<=n;i++) read(val[i]);
    up[1].first=1; up[1].second=1; down[1].first=1; down[1].second=1;
    for(ll i=2;i<=n;i++)
    {
//        cout<<"i:"<<i<<endl;
//        cout<<up[i-1].first<<" "<<up[i-1].second<<" "<<down[i-1].first<<" "<<down[i-1].second<<endl;
        if(val[i])
        {    
            if(up[i-1].first<val[i]-1 or (up[i-1].first<val[i] and up[i-1].second<2))
            {
                cout<<"-1"; return 0;
            }
            if(down[i-1].first>val[i] or (down[i-1].first==val[i] and down[i-1].second>=5))
            {
                cout<<"-1"; return 0;
            }
            if(up[i-1].first==val[i] and up[i-1].second>=5)
            {
                cout<<"-1"; return 0;
            }
            if(up[i-1].first>=val[i]) 
            {
                up[i].first=val[i];
                up[i].second=2;
            }
            else
            {
                up[i].first=val[i];
                up[i].second=1;
            }
            if(down[i-1].first==val[i]) 
            {
                down[i].first=down[i-1].first;
                down[i].second=down[i-1].second+1;
            }
            else 
            {
                down[i].first=val[i];
                down[i].second=1;
            }    
        }
        else
        {
            if(up[i-1].second<2)
            {
                up[i].first=up[i-1].first;
                up[i].second=up[i-1].second+1;
            }
            else
            {
                up[i].first=up[i-1].first+1;
                up[i].second=1;
            }
            if(down[i-1].second<5)
            {
                down[i].first=down[i-1].first;
                down[i].second=down[i-1].second+1;
            }
            else
            {
                down[i].first=down[i-1].first+1;
                down[i].second=1;
            }
        }
    }
    if(up[n].second>=2)
    {
        printf("%lld\n",up[n].first);
    }
    else
    {
        up[n].first=up[n].first-1;
        printf("%lld\n",up[n].first);
    }
    val[n]=up[n].first;
    ll temp=up[n].first;
    for(ll i=n-1;i>=1;i--)
    {
        if(!val[i])
        {
            temp=min(val[i+1],up[i].first);
            if(vis[temp]>=5) temp--;
            val[i]=temp;
        }
        vis[val[i]]++;
    }
    for(ll i=1;i<=n;i++) 
    {
        cout<<val[i]<<" ";
    }
    return 0;
}
C_Code

 

posted @ 2021-07-18 20:35  AaMuXiiiiii  阅读(22)  评论(0编辑  收藏  举报