1. 程式人生 > 其它 >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);
    }
}