noip模拟11
A. math
一个简单的找规律..考场上切了..
至此我们可以发现:很多数学题枚举找规律就能切切切切切!
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long int 4 #define lf double 5 #define mp make_pair 6 const ll N=1e6+50; 7 inline void read(ll &ss) 8 { 9 ss=0; bool cit=0; char ch; 10 while(!isdigit(ch=getchar())) if(ch=='-') cit=1; 11 while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar(); 12 if(cit) ss=-ss; 13 } 14 ll n,mod,sum,cnt; 15 ll val[N]; 16 ll gcd(ll a,ll b) 17 { 18 return b ? gcd(b,a%b) : a ; 19 } 20 signed main() 21 { 22 // freopen("1.in","r",stdin); 23 // freopen("out","w",stdout); 24 read(n); read(mod); 25 ll temp=mod; 26 for(ll i=1;i<=n;i++) 27 { 28 read(val[i]); val[i]%=mod; 29 temp=gcd(temp,val[i]); 30 } 31 printf("%lld\n",mod/temp); 32 for(ll i=0;i<mod;i+=temp) 33 { 34 printf("%lld ",i); 35 } 36 return 0; 37 } 38
LRX大佬在考场上打开测试数据之后发现:这道题的输出数据是一个等差数列..
于是 ta 打了一个随机化枚举到 850ms 直接切了..超大数据都卡不过.
所以这里再次安利随机化算法亦可玄学切切切..
B. biology
考场上打了一个记忆化搜索,但是这题卡的有点紧,但还是从 爆搜40pts -> 记忆化 60pts ..
正解是一个 O(nm) 的 dp..
#include<bits/stdc++.h> using namespace std; #define ll long long int #define lf double #define mp make_pair const ll N=2e3+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,alls,ans; struct I { ll num,val,x,y; } a[N*N]; struct II { ll l,r; } b[N*N]; ll f[N][N],f1,f2,f3,f4; inline bool comp(I aa,I bb) { return aa.num==bb.num ? aa.val>bb.val : aa.num<bb.num ; } signed main() { read(n); read(m); for(ll i=1;i<=n;i++) { for(ll j=1;j<=m;j++) { read(a[i*n-n+j].num); a[i*n-n+j].x=i; a[i*n-n+j].y=j; } } for(ll i=1;i<=n;i++) { for(ll j=1;j<=m;j++) { read(a[i*n-n+j].val); } } sort(a+1,a+1+n*m,comp); for(ll i=1;i<=n*m;i++) { if(a[i].num!=a[i-1].num) { b[alls].r=i-1; b[++alls].l=i; } } b[alls].r=n*m; for(ll i=b[1].l;i<=b[1].r;i++) { f1=max(f1,a[i].val+a[i].x+a[i].y); f2=max(f2,a[i].val+a[i].x-a[i].y); f3=max(f3,a[i].val-a[i].x+a[i].y); f4=max(f4,a[i].val-a[i].x-a[i].y); } ll maxn,maxn1,maxn2; for(ll i=2;i<=alls;i++) { for(ll j=b[i].l;j<=b[i].r;j++) { maxn1=max(f1-a[j].x-a[j].y,f2-a[j].x+a[j].y); maxn2=max(f3+a[j].x-a[j].y,f4+a[j].x+a[j].y); maxn=max(maxn1,maxn2); f[a[j].x][a[j].y]=maxn+a[j].val; ans=max(ans,f[a[j].x][a[j].y]); } for(ll j=b[i].l;j<=b[i].r;j++) { f1=max(f1,f[a[j].x][a[j].y]+a[j].x+a[j].y); f2=max(f2,f[a[j].x][a[j].y]+a[j].x-a[j].y); f3=max(f3,f[a[j].x][a[j].y]-a[j].x+a[j].y); f4=max(f4,f[a[j].x][a[j].y]-a[j].x-a[j].y); } } printf("%lld",ans); return 0; } /* 3 3 0 6 8 1 6 1 0 6 8 0 1 2 3 4 5 0 6 7 */
C. english
我们可以使用单调栈求出每个值作为最大值所覆盖的最大区间.
关于第一问,由于是求和,我们可以选择考虑二进制下每一位造成的贡献.
关于第二问,看到异或理应想到Trie树,发现这个是区间的最值,可以考虑可持久化.
#include<bits/stdc++.h> using namespace std; namespace BSS { #define ll long long int #define ull unsigend ll #define re register ll #define lf double #define lbt(x) (x&(-x)) #define mp(x,y) make_pair(x,y) #define lb lower_bound #define ub upper_bound #define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout) #define Fill(x,y) memset(x,y,sizeof x) #define Copy(x,y) memcpy(x,y,sizeof x) inline ll read() { ll ss=0; bool cit=1; char ch; while(!isdigit(ch=getchar())) if(ch=='-') cit=0; while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar(); return cit?ss:-ss; } } using namespace BSS; const ll N=1e5+51,mod=1e9+7; ll m,n,tail,ans,tot,opt; ll w[N],stk[N],cnt[N<<5],rt[N<<5],lst[N<<5]; ll tr[N<<5][2]; ll pre[N][20][2]; map<pair<ll,ll>,ll> map1; struct I { ll l,r; } p[N]; inline void Work_One(){ for(re i=1;i<=n;++i) for(re j=1;j<=20;++j) pre[i][j][1]+=pre[i-1][j][1]+((w[i]>>(j-1))&1), pre[i][j][0]+=pre[i-1][j][0]+(!((w[i]>>(j-1))&1)); ans=0; for(re i=1;i<=n;++i){ for(re j=1;j<=20;++j){ (ans+=(1ll<<(j-1))*(pre[p[i].r][j][1]-pre[i-1][j][1])%mod*(pre[i][j][0]-pre[p[i].l-1][j][0])%mod*w[i]%mod)%=mod; (ans+=(1ll<<(j-1))*(pre[p[i].r][j][0]-pre[i-1][j][0])%mod*(pre[i][j][1]-pre[p[i].l-1][j][1])%mod*w[i]%mod)%=mod; } } printf("%lld\n",ans); } inline void ins(ll now,ll pre,ll val){ ll p; for(ll i=20;~i;--i){ tr[now][0]=tr[pre][0],tr[now][1]=tr[pre][1]; p=(val>>(i-1))&1; tr[now][p]=++tot, now=tr[now][p],pre=tr[pre][p], cnt[now]=cnt[pre]+1; } } inline ll query(ll l,ll r,ll val,ll x){ ll p,res=0,sum=0; for(ll i=20;~i;--i){ p=(val>>(i-1))&1; if(cnt[tr[r][p^1]]>cnt[tr[l][p^1]]){ if((res+(1ll<<(i-1)))>x) (sum+=cnt[tr[r][p^1]]-cnt[tr[l][p^1]])%=mod,r=tr[r][p],l=tr[l][p]; else res=(res+(1ll<<(i-1)))%mod,r=tr[r][p^1],l=tr[l][p^1]; } else r=tr[r][p],l=tr[l][p]; } return sum; } inline void Work_Two(){ ans=0; map1.clear(); rt[0]=++tot,lst[tot]=-1; ins(rt[0],0,0); for(re i=1;i<=n;++i) ins((rt[i]=++tot),rt[i-1],w[i]); for(re i=1;i<=n;++i){ if(i-p[i].l>p[i].r-i){ for(re j=i;j<=p[i].r;++j){ (ans+=(query(rt[p[i].l-1],rt[i],w[j],w[i])*w[i]))%=mod; } } else{ for(re j=p[i].l;j<=i;++j){ (ans+=(query(rt[i-1],rt[p[i].r],w[j],w[i])*w[i]))%=mod; } } } printf("%lld\n",ans); } inline void Work(){ ll l,r,temp; for(re i=1;i<=n;i++) if(!tail){ p[i].l=i,stk[++tail]=i; } else{ if(w[stk[tail]]>w[i]) p[i].l=i,stk[++tail]=i; else{ r=i-1,l=N; while(tail and w[stk[tail]]<=w[i]){ temp=stk[tail--],p[temp].r=i-1, l=p[temp].l; } p[i].l=l,stk[++tail]=i; } } while(tail) temp=stk[tail--],p[temp].r=n; if(opt&1) Work_One(); if(opt&2) Work_Two(); } signed main(){ n=read(),opt=read(); for(re i=1;i<=n;i++) w[i]=read(); Work(); return 0; }