noip模拟4

赛时rank 6,T1 20,T2 55,T3 100,T4 0

悔了,我赛时应该先开T3T4的。看了两个小时的T1不会做,T4一眼切了没时间打了

Cai

由于一些不可抗力因素,直接挂原题链接了

T1 最短路

[USACO09DEC] Cow Toll Paths G

solution:

我们发现n很小,考虑floyd

正常的floyd可以解决边权之和最小值,那么如何让其顺带着解决点权最大值捏?

将点按照点权从小到大排序就可以啦

disti,j=min{disti,j,disti,k+distk,j}
这个是floyd原数组,但是因为点按照点权排过序,所以转化一下即可。

ansi,j=min{ansi,j,disti,j+max{val(i),val(j),val(k)}}
这是统计答案的数组,记得转化

code:

点此查看代码
#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 方格取数

[POI2008] KUP-Plot purchase

solution:

有一个二分套二分加卡常的O(n2log2n)做法,没有好好处理,瞎写的,但是因为学校数据水,于是就过了,在luogu上没有,挂一下吧。看代码很好理解的。

点此查看代码
#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

正解是O(n2)的悬线法

考虑>2k的肯定不选,在[k,2k]的就是答案,所以就转化为了求<k的元素的一个矩阵,使得其的和在区间中。

如果最大的子矩阵的和sumk,那么就一定可以找到一个最大子矩阵的子矩阵满足条件。

取出其第一行的和sum1

如果sum1k,答案就在第一行,一个一个删即可。

反之,直接舍弃。

code:

点此查看代码
#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 数组

solution:

Please, another Queries on Array?

大水题。

考虑

φ(n)=npPrime&p|np1p

φ(kn)=knpPrime&p|knp1p

就是考虑有几个素因子呗,考虑到插入的数很小,将300以内的素数预处理出来,大概是有62个,用一个bitset判断是否出现过,线段树维护区间乘积,区间的bitset,由于乘积会很大,需要取模,就要预处理逆元。

具体看代码吧,比较好理解。

code:

点此查看代码
#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 树

solution:

一眼根号分治,赛场没时间打了。现在也没时间。我要去水,晚上在写。

update:
总共有两种做法

  1. 求k级祖先,根号分治预处理,比较板子(好像可以用长链剖分O(1)求k级祖先,复杂度较优)
  2. 利用树剖的特性,将树排成dfs序,在序列上分块进行维护

等放假了再打吧,先去学四边形不等式了,逃

posted @   CuFeO4  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示