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; }
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 */
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; }