noip模拟4
赛时rank 6,T1 20,T2 55,T3 100,T4 0
悔了,我赛时应该先开T3T4的。看了两个小时的T1不会做,T4一眼切了没时间打了
由于一些不可抗力因素,直接挂原题链接了
T1 最短路
我们发现
正常的
将点按照点权从小到大排序就可以啦
这个是
这是统计答案的数组,记得转化
点此查看代码
#include<bits/stdc++.h> using namespace std; #define int long long struct node{ int value,dis; friend bool operator < (const node &x,const node &y){ return x.value<y.value; } }a[999999]; int edge[400][400]; int n,m,q; int ans[400][400]; #define infile(x) freopen(x,"r",stdin) #define outfile(x) freopen(x,"w",stdout) #define errfile(x) freopen(x,"w",stderr) using ll=long long;using ull=unsigned long long; #ifdef LOCAL FILE *InFile=infile("in.in"),*OutFile=outfile("out.out"); #else FILE *InFile=infile("path.in"),*OutFile=outfile("path.out"); #endif signed main(){ memset(edge,0x3f,sizeof edge); memset(ans,0x3f,sizeof ans); ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); cin>>n>>m>>q; for(int i=1;i<=n;++i){ cin>>a[i].value; a[i].dis=i; edge[i][i]=0; } for(int i=1;i<=m;++i){ int x,y,z; cin>>x>>y>>z; edge[x][y]=edge[y][x]=min(edge[x][y],z); } sort(a+1,a+1+n); for(int k=1;k<=n;++k){ for(int i=1;i<=n;++i){ for(int j=1;j<=n;++j){ edge[a[i].dis][a[j].dis]=min(edge[a[i].dis][a[j].dis],edge[a[i].dis][a[k].dis]+edge[a[k].dis][a[j].dis]); ans[a[i].dis][a[j].dis]=min(ans[a[i].dis][a[j].dis],edge[a[i].dis][a[j].dis]+max({a[i].value,a[j].value,a[k].value})); } } } while(q--){ int x,y; cin>>x>>y; cout<<(ans[x][y]==ans[0][0]?-1:ans[x][y])<<'\n'; } }
T2 方格取数
有一个二分套二分加卡常的
点此查看代码
#include<bits/stdc++.h> #include<bits/extc++.h> // using namespace __gnu_pbds; // using namespace __gnu_cxx; using namespace std; #define infile(x) freopen(x,"r",stdin) #define outfile(x) freopen(x,"w",stdout) #define errfile(x) freopen(x,"w",stderr) using ll=long long;using ull=unsigned long long; #ifdef LOCAL FILE *InFile=infile("in.in"),*OutFile=outfile("out.out"); // FILE ErrFile=errfile("err.err"); #else // FILE *InFile=infile("matrix.in"),*OutFile=outfile("matrix.out"); #endif namespace IO { #ifdef LOCAL FILE *Fin(fopen("in.in", "r")), *Fout(fopen("out.out", "w")); #else FILE *Fin(fopen("matrix.in", "r")), *Fout(fopen("matrix.out", "w")); #endif class qistream { static const size_t SIZE = 1 << 24, BLOCK = 64; FILE *fp; char buf[SIZE]; int p; public: qistream(FILE *_fp = stdin): fp(_fp), p(0) { fread(buf + p, 1, SIZE - p, fp); } void flush() { memmove(buf, buf + p, SIZE - p), fread(buf + SIZE - p, 1, p, fp), p = 0; } qistream &operator>>(char &str) { str = getch(); while (isspace(str)) str = getch(); return*this; } template<class T>qistream &operator>>(T &x) { x = 0; p + BLOCK >= SIZE ? flush() : void(); bool flag = false; for (; !isdigit(buf[p]); ++p) flag = buf[p] == '-'; for (; isdigit(buf[p]); ++p) x = x * 10 + buf[p] - '0'; x = flag ? -x : x; return*this; } char getch() { return buf[p++]; } qistream &operator>>(char *str) { char ch = getch(); while (ch <= ' ') ch = getch(); int i; for (i = 0; ch > ' '; ++i, ch = getch()) str[i] = ch; str[i] = '\0'; return*this; } } qcin(Fin); class qostream { static const size_t SIZE = 1 << 24, BLOCK = 64; FILE *fp; char buf[SIZE]; int p; public: qostream(FILE *_fp = stdout): fp(_fp), p(0) {}~qostream() { fwrite(buf, 1, p, fp); } void flush() { fwrite(buf, 1, p, fp), p = 0; } template<class T>qostream &operator<<(T x) { int len = 0; p + BLOCK >= SIZE ? flush() : void(); x < 0 ? (x = -x, buf[p++] = '-') : 0; do buf[p + len] = x % 10 + '0', x /= 10, ++len; while (x) ; for (int i = 0, j = len - 1; i < j; ++i, --j) swap(buf[p + i], buf[p + j]); p += len; return*this; } qostream &operator<<(char x) { putch(x); return*this; } void putch(char ch) { p + BLOCK >= SIZE ? flush() : void(); buf[p++] = ch; } qostream &operator<<(char *str) { for (int i = 0; str[i]; ++i) putch(str[i]); return*this; } } qcout(Fout); } using namespace IO; #define cin qcin #define cout qcout const int N = 2010; ll sum[N][N],k; int n; inline ll get(int i,int j,int i1,int j1){ return sum[i][j]-sum[i1-1][j]-sum[i][j1-1]+sum[i1-1][j1-1]; } signed main(){ //cin.tie(nullptr)->sync_with_stdio(false); //cout.tie(nullptr)->sync_with_stdio(false); cin>>n>>k; for(int i = 1;i <= n; ++i) for(int j = 1;j <= n; ++j) cin>>sum[i][j]; for(int i = 1;i <= n; ++i){ for(int j = 1;j <= n; ++j) sum[i][j] = sum[i][j]-sum[i-1][j-1]+sum[i-1][j]+sum[i][j-1]; } for(int i = 1;i <= n; ++i){ for(int j = 1;j <= n; ++j){ int L = 1,R = i; while(L<=R){ int i1 = (L+R)>>1; int l = 1,r = j; ll mx = 0,mn = LLONG_MAX; while(l<=r){ int j1 = (l+r)>>1; ll emm = get(i,j,i1,j1); mx = max(mx,emm); mn = min(mn,emm); if(emm > k*2) {l = j1+1;continue;} if(emm < k) {r = j1-1;continue;} cout<<i1<<' '<<j1<<' '<<i<<' '<<j<<'\n'; return 0; } if(mx > k*2) L = i1+1; if(mn < k) R = i1-1; } } } cout<<-1; }
有些人不会写二维前缀和现推的还推错了,白搭10min
正解是
考虑
如果最大的子矩阵的和
取出其第一行的和
如果
反之,直接舍弃。
点此查看代码
#include<bits/stdc++.h> #include<bits/extc++.h> // using namespace __gnu_pbds; // using namespace __gnu_cxx; using namespace std; #define infile(x) freopen(x,"r",stdin) #define outfile(x) freopen(x,"w",stdout) #define errfile(x) freopen(x,"w",stderr) using ll=long long;using ull=unsigned long long; #ifdef LOCAL FILE *InFile=infile("in.in"),*OutFile=outfile("out.out"); // FILE ErrFile=errfile("err.err"); #else #endif const int N = 2010; int n,l[N][N],r[N][N],h[N][N]; ll k,sum[N][N],val[N][N]; inline ll get(int a,int b,int c,int d){ return sum[c][d] - sum[a - 1][d] - sum[c][b - 1] + sum[a - 1][b - 1]; } inline void Work(int a,int b,int c,int d){ while(get(a,b,c,d) > 2*k){ if(a == c) d--; else if(get(a,b,c,d) >= k) c = a; else a++; } cout<<b<<' '<<a<<' '<<d<<' '<<c<<'\n'; exit(0); } signed main(){ cin.tie(nullptr)->sync_with_stdio(false); cout.tie(nullptr)->sync_with_stdio(false); cin>>k>>n; for(int i = 1;i <= n; ++i){ for(int j = 1;j <= n; ++j){ cin>>sum[i][j]; val[i][j] = sum[i][j]; if(k <= val[i][j] && val[i][j] <= 2*k) return cout<<j<<' '<<i<<' '<<j<<' '<<i<<'\n',0; } } for(int i = 1;i <= n; ++i){ for(int j = 1;j <= n; ++j){ sum[i][j] = sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+val[i][j]; } } for(int i = 1;i <= n; ++i) r[0][i] = n+1; for(int i = 1;i <= n; ++i){ for(int j = 1;j <= n; ++j){ if(val[i][j] <= 2*k) h[i][j] = h[i-1][j]+1; } } for(int i = 1;i <= n; ++i){ int res = 0; for(int j = 1;j <= n; ++j){ if(h[i][j]) l[i][j] = max(l[i-1][j],res); else res = j,l[i][j] = 0; } res = n + 1; for(int j = n; j; --j){ if(h[i][j]) r[i][j] = min(r[i-1][j],res); else res = j,r[i][j] = n + 1; } } for(int i = 1;i <= n; ++i){ for(int j = 1;j <= n; ++j){ if(!h[i][j]) continue; int a = i - h[i][j] + 1; int b = l[i][j] + 1; int d = r[i][j] - 1 ; if(get(a,b,i,d) < k) continue; Work(a,b,i,d); } } cout<<"NIE"; }
T3 数组
Please, another Queries on Array?
大水题。
考虑
就是考虑有几个素因子呗,考虑到插入的数很小,将300以内的素数预处理出来,大概是有62个,用一个bitset判断是否出现过,线段树维护区间乘积,区间的bitset,由于乘积会很大,需要取模,就要预处理逆元。
具体看代码吧,比较好理解。
点此查看代码
#include<bits/stdc++.h> #include<bits/extc++.h> // using namespace __gnu_pbds; // using namespace __gnu_cxx; using namespace std; #define infile(x) freopen(x,"r",stdin) #define outfile(x) freopen(x,"w",stdout) #define errfile(x) freopen(x,"w",stderr) using ll=long long;using ull=unsigned long long; #ifdef LOCAL FILE *InFile=infile("in.in"),*OutFile=outfile("out.out"); // FILE *ErrFile=errfile("err.err"); #else FILE *InFile=infile("array.in"),*OutFile=outfile("array.out"); #endif // #define int long long const int N = 1e5 + 10,mod = 1e9 + 7; int pos[300]; vector<int> prime={2,3,5,7,11,13,17,19, 23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97, 101,103,107,109,113,127,131,137,139,149,151, 157,163,167,173,179,181,191,193,197,199,211,223,227, 229,233,239,241,251,257,263,269,271,277,281,283,293}; inline int power(int a,int b,int mod){ int res = 1; while(b){ if(b&1) res = 1ll*res*a%mod; b>>=1;a = 1ll*a*a%mod; } return res; } int n,a[N],q,inv[N]; bitset<65> pre[310]; struct Segment_Tree{ private: struct segment_tree{ int l,r; ll val,lazy1 = 1; bitset<65> pd_prime,lazy2; #define l(x) tree[x].l #define r(x) tree[x].r #define val(x) tree[x].val #define lazy1(x) tree[x].lazy1 #define lazy2(x) tree[x].lazy2 #define pd(x) tree[x].pd_prime }tree[N<<2]; inline void pushup(int k){ val(k) = val(k<<1)*val(k<<1|1)%mod; tree[k].pd_prime=(tree[k<<1].pd_prime|tree[k<<1|1].pd_prime); } inline void pushdown(int k){ if(lazy1(k)!=1){ int ls =k<<1,rs = k<<1|1; val(ls) = 1ll*val(ls)*power(lazy1(k),r(ls)-l(ls)+1,mod)%mod; lazy1(ls) = lazy1(ls)*lazy1(k)%mod; lazy2(ls) |= lazy2(k); pd(ls)|=lazy2(k); val(rs) = 1ll*val(rs)*power(lazy1(k),r(rs)-l(rs)+1,mod)%mod; pd(rs)|=lazy2(k); lazy1(rs) = lazy1(rs)*lazy1(k)%mod; lazy2(rs) |= lazy2(k); lazy2(k).reset(); lazy1(k)=1; } } public: void build(int k,int l,int r){ l(k) = l,r(k) = r; if(l == r){ val(k) = a[l]; tree[k].pd_prime = pre[val(k)]; return; } int mid = (l+r)>>1; build(k<<1,l,mid);build(k<<1|1,mid+1,r); pushup(k); } void update(int k,int l,int r,int val,bitset<65> prim){ if(l <= l(k) && r(k) <= r){ val(k) = 1ll*val(k)*power(val,r(k)-l(k)+1,mod)%mod; pd(k)|=prim; lazy1(k) = 1ll*lazy1(k)*val%mod; lazy2(k) |= prim; return; } pushdown(k); int mid = (l(k)+r(k))>>1; if(l <= mid) update(k<<1,l,r,val,prim); if(r > mid) update(k<<1|1,l,r,val,prim); pushup(k); } pair<ll,bitset<65> > query(int k,int l,int r){ if(l <= l(k) && r(k) <= r) return make_pair(val(k),pd(k)); pushdown(k); int mid = (l(k)+r(k))>>1; pair<ll,bitset<65> > res;res.first = 1; if(l <= mid){ pair<ll,bitset<65> > ll = query(k<<1,l,r); res.first = res.first*ll.first%mod; res.second|=ll.second; } if(r > mid){ pair<ll,bitset<65> > ll = query(k<<1|1,l,r); res.first = res.first*ll.first%mod; res.second|=ll.second; } return res; } }T; signed main(){ cin.tie(nullptr)->sync_with_stdio(false); cout.tie(nullptr)->sync_with_stdio(false); for(int i = 0;i < prime.size(); ++i) pos[prime[i]] = i; for(auto i:prime) inv[i] = power(i,mod-2,mod); for(int x = 1;x <= 300; ++x){ for(auto i : prime){ if(i > x) break; if(x % i == 0) pre[x][pos[i]] = true; } } cin>>n>>q; for(int i = 1;i <= n; ++i) cin>>a[i]; T.build(1,1,n); int op,l,r,x; while(q--){ cin>>op>>l>>r; if(op == 1){ cin>>x; T.update(1,l,r,x,pre[x]); } else{ pair<ll,bitset<65> > res = T.query(1,l,r); ll ans = res.first; for(auto i:prime){ if(res.second[pos[i]]){ ans = 1ll*ans*(i-1)%mod*inv[i]%mod; } } cout<<ans<<'\n'; } } }
T4 树
一眼根号分治,赛场没时间打了。现在也没时间。我要去水,晚上在写。
update:
总共有两种做法
- 求k级祖先,根号分治预处理,比较板子(好像可以用长链剖分
求k级祖先,复杂度较优) - 利用树剖的特性,将树排成dfs序,在序列上分块进行维护
等放假了再打吧,先去学四边形不等式了,逃
__________________________________________________________________________________________
本文来自博客园,作者:CuFeO4,转载请注明原文链接:https://www.cnblogs.com/hzoi-Cu/p/18298506
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】