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);
}
}