其他分享
首页 > 其他分享> > NOIP 模拟 七十二

NOIP 模拟 七十二

作者:互联网

估分 100+70+30+10=210。实际 100+82+100+10=292。

T2 测试点不够 20 个,T3 hs暴力加剪枝跑的飞快。

T1 T1出了个大阴间题

T1 的数据范围 $n\le 18 $,显然提示要去装压。分析一下 a,b 的变化,b 就是个摆设,而 a 的变化只有 a 和 a+1,所以可以暴力枚举 dp。注意离散化。

dp 状态为当前选了那些,a 为多少。转移的话就是枚举下一个选谁就行。

#include<bits/stdc++.h>
#define int long long 
#define mod 1000000007
using namespace std;
struct zxb
{int num,a,b,sum;
}dp[1<<18][39];
int n,a[38],san[1111],tot,U,xi;
signed main()
{   freopen("repair.in","r",stdin);
    freopen("repair.out","w",stdout);
    scanf("%lld%lld",&n,&xi);U=(1<<n)-1;
    for(int i=1;i<=n;++i)scanf("%lld",&a[i]),san[++tot]=a[i],san[++tot]=a[i]+1;
    sort(san+1,san+1+tot);tot=unique(san+1,san+1+tot)-san-1;
    for(int i=1;i<=n;++i)dp[1<<i-1][lower_bound(san+1,san+1+tot,a[i])-san]=(zxb){1,a[i],0,0};
    for(int i=1;i<U;++i)
    for(int j=1;j<=tot;++j)
    if(dp[i][j].num)
    {   for(int k=1;k<=n;++k)
        if(!(i&(1<<k-1)))
        {   int newa=dp[i][j].a==a[k]?a[k]+1:max(dp[i][j].a,a[k]);
            int id=lower_bound(san+1,san+1+tot,newa)-san,w=(i|(1<<k-1));
            dp[w][id]=(zxb){(dp[w][id].num+dp[i][j].num)%mod,newa,2*dp[i][j].b+1,(dp[w][id].sum+(xi*newa%mod+dp[i][j].b)%mod*dp[i][j].num%mod+dp[i][j].sum)%mod};
        }
    }
    for(int i=tot;i;--i)
    if(dp[U][i].num){printf("%lld %lld\n",dp[U][i].a,dp[U][i].sum);return 0;}
}

T2 T2 最简单辣快来做

T2 简单分析了一波,感觉有绝对值肯定要去掉,然后联想到 欧几里得距离 的多方向讨论,想到要将平面分四块求四个方向的 ans。这样 $O(n^2) $ 维护前缀和,然后 $O(1)$ 回答。只不过是需要乘上逆元。

因为不保证互质,所以会挂。

正解就是对前缀和定义为前缀点对当前点的贡献和,转移的过程乘上对应的 a,b。然后仍然是 $O(1)$ 查询。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,q,w,hei,mod,a,b,h[2001],xi[2001],yi[2001],san1[2050],san2[2050],tot1,tot2,c[2012][2012][5];
int inva,invb,x,y;
int powa[100001],powb[100001],qpowa[100001],qpowb[100001];
const int inf=1e18;
inline int qpa(int b){if(b<0)return 0;return qpowa[b/100000]*powa[b%100000]%mod;}
inline int qpb(int b){if(b<0)return 0;return qpowb[b/100000]*powb[b%100000]%mod;}
signed main()
{   freopen("satellite.in","r",stdin);
    freopen("satellite.out","w",stdout);
    scanf("%lld%lld%lld%lld%lld%lld%lld",&n,&q,&w,&hei,&mod,&a,&b);
    for(int i=1;i<=n;++i)
    {   scanf("%lld%lld%lld",&h[i],&xi[i],&yi[i]);
        san1[++tot1]=xi[i];san2[++tot2]=yi[i];
    }  
    powa[0]=1,powb[0]=1;qpowa[0]=1;qpowb[0]=1;
    for(int i=1;i<=100000;++i)powa[i]=powa[i-1]*a%mod,powb[i]=powb[i-1]*b%mod;
    for(int i=1;i<=100000;++i)qpowa[i]=qpowa[i-1]*powa[100000]%mod,qpowb[i]=qpowb[i-1]*powb[100000]%mod;
    sort(san1+1,san1+1+tot1);tot1=unique(san1+1,san1+1+tot1)-san1-1;
    sort(san2+1,san2+1+tot2);tot2=unique(san2+1,san2+1+tot2)-san2-1;
    for(int i=1;i<=n;++i)
    {   int x=lower_bound(san1+1,san1+1+tot1,xi[i])-san1;
        int y=lower_bound(san2+1,san2+1+tot2,yi[i])-san2;
        (c[x][y][1]+=h[i])%=mod;(c[x][y][2]+=h[i])%=mod;(c[x][y][3]+=h[i])%=mod;(c[x][y][4]+=h[i])%=mod;
    }
    for(int i=1;i<=tot1;++i)for(int j=1;j<=tot2;++j)
    c[i][j][1]=(c[i][j][1]+c[i-1][j][1]*qpa(san1[i]-san1[i-1])%mod+c[i][j-1][1]*qpb(san2[j]-san2[j-1])%mod-c[i-1][j-1][1]*qpa(san1[i]-san1[i-1])%mod*qpb(san2[j]-san2[j-1])%mod+mod)%mod;
    for(int i=tot1;i;--i)for(int j=1;j<=tot2;++j)
    c[i][j][2]=(c[i][j][2]+c[i+1][j][2]*qpa(san1[i+1]-san1[i])%mod+c[i][j-1][2]*qpb(san2[j]-san2[j-1])%mod-c[i+1][j-1][2]*qpa(san1[i+1]-san1[i])%mod*qpb(san2[j]-san2[j-1])%mod+mod)%mod;
    for(int i=1;i<=tot1;++i)for(int j=tot2;j;--j)
    c[i][j][3]=(c[i][j][3]+c[i-1][j][3]*qpa(san1[i]-san1[i-1])%mod+c[i][j+1][3]*qpb(san2[j+1]-san2[j])%mod-c[i-1][j+1][3]*qpa(san1[i]-san1[i-1])%mod*qpb(san2[j+1]-san2[j])%mod+mod)%mod;
    for(int i=tot1;i;--i)for(int j=tot2;j;--j)
    c[i][j][4]=(c[i][j][4]+c[i+1][j][4]*qpa(san1[i+1]-san1[i])%mod+c[i][j+1][4]*qpb(san2[j+1]-san2[j])%mod-c[i+1][j+1][4]*qpa(san1[i+1]-san1[i])%mod*qpb(san2[j+1]-san2[j])%mod+mod)%mod;
    for(int i=1;i<=q;++i)
    {   int x,y,ans=0;scanf("%lld%lld",&x,&y);
        int pos1=lower_bound(san1+1,san1+1+tot1,x)-san1;
        int pos2=lower_bound(san2+1,san2+1+tot2,y)-san2;
        ans=(ans+c[pos1-1][pos2-1][1]*qpa(x-san1[pos1-1])%mod*qpb(y-san2[pos2-1])%mod)%mod; 
        ans=(ans+c[pos1][pos2-1][2]*qpa(san1[pos1]-x)%mod*qpb(y-san2[pos2-1])%mod)%mod;
        ans=(ans+c[pos1-1][pos2][3]*qpa(x-san1[pos1-1])%mod*qpb(san2[pos2]-y)%mod)%mod;
        ans=(ans+c[pos1][pos2][4]*qpa(san1[pos1]-x)%mod*qpb(san2[pos2]-y)%mod)%mod;
        printf("%lld\n",ans);
    }
}

T3 T3 是我的你不要抢

hs 果然是万能的。。

对于长度大于等于 $\sqrt {L}$ 的只有 $O(\sqrt {L})$ 个,处理它们两两之间答案。
否则只要存在一个长度小于 $\sqrt {L}$ 的,就可以直接 $O(\sqrt {L})$ 比较。
复杂度 $O((L + Q)\sqrt {L})$,期望得分 $70 \sim 100$。

这似乎是 hs 复杂度的证明。。

如果把所有串建出 AC 自动机。设 B 满足 S = S′+ B,T = B + T ′,则 S 在
fail 树上到祖先链里恰好有 B。
我们要最大化这个 B,其实是要求 trie 树上根到 T 的链,与 fail 树上,根到
S 的链,并的深度最大的节点。
将问题离线,在 trie 上 dfs,每次把当前点的信息加入数据结构,dfs 到 T 处
时查询 S 处的答案。
直接使用树链剖分,时间复杂度 $ O(n log^2n)$,期望得分 $70 \sim 100$。
考虑我们的操作只是子树max,单点查询,考虑标记永久化后使用可回退数据
结构。时间复杂度 $ O(n log n) $,期望得分 100。

#include<bits/stdc++.h>
#define N 600005
#define mod 131
using namespace std;
int n,m,q;
string a[N];
vector<unsigned long long >hs[N];
map<pair<int,int>,int>mp;
unsigned long long jc[N];
signed main()
{   freopen("string.in","r",stdin);
    freopen("string.out","w",stdout);
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;++i)
    {   cin>>a[i];unsigned long long hss=0;
        hs[i].push_back(hss);
        for(int j=0;j<a[i].size();++j)hs[i].push_back(hss=hss*mod+a[i][j]-'a'+1);
    }
    jc[0]=1;
    for(int i=1;i<=N-1;++i)jc[i]=jc[i-1]*mod;
    for(int i=1;i<=q;++i)
    {   int x,y;
        scanf("%d%d",&x,&y);
        if(mp.find(make_pair(x,y))!=mp.end()){printf("%d\n",mp[make_pair(x,y)]);continue;}
        int len=min(a[x].size(),a[y].size());
        int ans=0,len1=a[x].size();
        for(int j=len;j;--j)
        {   if(hs[y][j]==hs[x][len1]-hs[x][len1-j]*jc[j]){ans=j;break;}
        }
        mp[make_pair(x,y)]=ans;
        printf("%d\n",ans);
    }
}

T4 显然也是我整的


#include<bits/stdc++.h>
#define N 2000001
#define int long long
using namespace std;
int f[N],t,n,m,a[N],ans,tong[N],zhi;
set<int>st,tmp;
inline int solve(int res)
{   int tt=0,gcd=0;
    if(*st.begin()>res/2)
    {   int B=*st.begin()*2-res;tt+=B;res-=B;zhi=0;
        set<int>::iterator it=st.begin();
        while(it!=st.end())tong[++zhi]=*it-B,++it;
        st.clear();for(int i=1;i<=zhi;++i)st.insert(tong[i]);
    }
    for(auto i:st)if(i<=res/2)gcd=__gcd(gcd,i);else break;
    while(st.size() and *st.begin()<=res/2)st.erase(st.begin());
    for(auto i:st)if(gcd+i<=res)gcd=__gcd(i,gcd);else break;
    while(st.size() and *st.begin()<=res-gcd)st.erase(st.begin());
    if(!st.size())return tt+gcd;
    int newres=res%gcd+gcd;zhi=0;
    for(auto i:st)tong[++zhi]=i+newres-res;st.clear();
    for(int i=1;i<=zhi;++i)st.insert(tong[i]);st.insert(gcd);
    return tt+solve(newres); 
}
signed main()
{   freopen("graph.in","r",stdin);
    freopen("graph.out","w",stdout);
    scanf("%lld",&t);
    while(t--)
    {   scanf("%lld%lld",&n,&m);
        for(int i=1,x;i<=m;++i)scanf("%lld",&x),st.insert(x);
        ans=solve(n);printf("%lld\n",ans);
    }
}

标签:NOIP,int,long,st,sqrt,七十二,100,模拟,define
来源: https://www.cnblogs.com/zhaoxubing/p/15387041.html