[考试总结]noip模拟37
然后今天暴力还是没有打满。。。。。。
考场心态复原:
第一题:这不就是一个扩展欧几里的嘛,简单。。
然后疯狂开始码,然后就过了样例,并且过了大样例。
之后继续看第二题,好像是个原题,然后发现不是,然后开第三题。
之后分析一波,发现中转边,然后只用一下子push进去几个起点就行,
然后也是一发大样例。
之后看第四题:
“怎么说也有200了,水个暴力就行了。。。”
然后。。。。
第四题抱零。。。。
还是不能掉以轻心。。。
数列
扩展欧几里的求不定方程。
对于形如 \(a*x_0 + b*y_0 = n\) 的不定方程为了求解 \(x_0\) 和 \(y_0\),可以通过扩展欧几里得先求出满足 \(a*x + b*y = gcd(a, b)\) 的 \(x\) 和 \(y\) 。容易得到,若 \(gcd(a, b)|(x-y)((x-y)%gcd(a,b)==0)\) ,则该不定方程有整数解,否则无符合条件的整数解。得到 \(x\) 和 \(y\) 后,可以通过 \(x_0 = x*n / gcd(a, b)\) 这个 \(x_0\) 相当关键,求出 \(x_0\).
然后就行了。。。
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define int long long
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
#define asm(i,x) for(register signed i=head[x];i;i=edge[i].next)
namespace xin_io
{
#define debug cout<<"debug"<<endl
#define sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
char buf[1<<20],*p1 = buf,*p2 = buf; int ak; typedef long long ll; typedef unsigned long long ull;
class xin_stream{public:template<typename type>inline xin_stream &operator >> (type &x)
{
register type s = 0; register int f = 1; register char ch = gc();
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = gc();}
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return x = s * f,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+7; const ll llinf = 1e18+7;
namespace xin
{
int x,y;
inline int abs(int x) {return x < 0 ? -x : x;}
int exgcd(int a,int b)
{
int ret,temp;
if( b == 0) {x = 1; y = 0;return a;}
int d = exgcd(b,a%b);
temp = x;x = y; y = temp - a/b * y;
return d;
}
inline int get_y(int a,int b,int x,int he){return (he - a * x) / b;}
int ans = 0;
int n,a,b,c[maxn];
inline short main()
{
io >> n >> a >> b;
a = abs(a); b = abs(b);
if(a > b) std::swap(a,b);
int gcd = exgcd(a,b);
a /= gcd; b /= gcd;
try(i,1,n)
{
io >> c[i],c[i] = abs(c[i]);
if(c[i] % gcd) {puts("-1"); exit(0);}
c[i] /= gcd;
}
try(i,1,n)
{
register int k = c[i] % b;
int zhuanx = x * k; int zhuany = y * k + (c[i] / b);
// cout<<zhuanx<<' '<<zhuany<<endl;
register int temp = abs(zhuanx) + abs(zhuany);
if(zhuanx > 0)
{
int zhuan = abs(zhuanx) / b;
zhuanx -= zhuan * b; zhuany += zhuan * a;
temp = std::min(temp,abs(zhuanx) + abs(zhuany));
temp = std::min(temp,abs(zhuanx-b) + abs(zhuany+a));
}
else if(zhuanx < 0)
{
int zhuan = abs(zhuanx) / b;
zhuanx += zhuan * b; zhuany -= zhuan * a;
temp = std::min(temp,abs(zhuanx) + abs(zhuany));
temp = std::min(temp,abs(zhuanx+b) + abs(zhuany-a));
}
ans += temp;
}
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
数对
状态转移方程:
\(f_{i,j}\) 表示前 \(i\) 个,然后最大的 \(a_i\) 为 \(j\) 的最大权值和。
然后注意数组就有 \(60pts\)
然后发现其实线段树可以维护,之后愉快 \(AC\)
\(60pts\)
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
#define asm(i,x) for(register signed i=head[x];i;i=edge[i].next)
namespace xin_io
{
#define debug cout<<"debug"<<endl
#define sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
char buf[1<<20],*p1 = buf,*p2 = buf; int ak; typedef long long ll; typedef unsigned long long ull;
class xin_stream{public:template<typename type>inline xin_stream &operator >> (type &x)
{
register type s = 0; register int f = 1; register char ch = gc();
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = gc();}
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return x = s * f,*this;
}}io;
}
#define int long long
using namespace xin_io; static const int maxn = 3e3+10,inf = 1e9+7; const ll llinf = 1e18+7;
namespace xin
{
class xin_seg
{
private:
#define ls(fa) (fa << 1)
#define rs(fa) (fa << 1 | 1)
inline void up(int fa){t[fa].s = std::max(t[ls(fa)].s ,t[rs(fa)].s);}
inline void down(int fa)
{
if(!t[fa].debt) return;
t[ls(fa)].s += t[fa].debt ; t[rs(fa)].s += t[fa].debt;
t[ls(fa)].debt += t[fa].debt; t[rs(fa)].debt += t[fa].debt;
t[fa].debt = 0;
}
public:
class xin_tree{public:int s,debt;}t[maxn*1000];
void update(int fa,int l,int r,int ql,int qr,int val)
{
if(ql <= l and qr >= r) {t[fa].s += val; t[fa].debt += val; return ;}
register int mid = l + r >> 1;
down(fa);
if(ql <= mid) update(ls(fa),l,mid,ql,qr,val);
if(qr > mid) update(rs(fa),mid+1,r,ql,qr,val);
up(fa);
}
void modify(int fa,int l,int r,int pos,int val)
{
if(l == r) {t[fa].s = std::max(val,t[fa].s); return;}
register int mid = l + r >> 1;
down(fa);
if(pos <= mid) modify(ls(fa),l,mid,pos,val);
else modify(rs(fa),mid+1,r,pos,val);
up(fa);
}
int query(int fa,int l,int r,int ql,int qr)
{
if(ql <= l and qr >= r) return t[fa].s;
register int mid = l + r >> 1,ret = 0;
down(fa);
if(ql <= mid) ret = std::max(ret,query(ls(fa),l,mid,ql,qr));
if(qr > mid) ret = std::max(ret,query(rs(fa),mid+1,r,ql,qr));
return ret;
}
}t;
class xin_data
{
private:
friend bool operator < (xin_data x,xin_data y)
{return (x.a + x.b) < (y.a + y.b);}
public:
int a,b,w;
}d[maxn];
int n;
int lisan[maxn * 1000],cnt = 0;
int f[maxn][maxn + 3000];
inline short main()
{
io >> n;
try(i,1,n)
{
io >> d[i].a >> d[i].b >> d[i].w;
lisan[++cnt] = d[i].a; lisan[++cnt] = d[i].b;
}
std::sort(lisan+1,lisan+cnt+1);
int k = std::unique(lisan+1,lisan+cnt+1) - (lisan + 1);
try(i,1,n)
{
d[i].a = std::lower_bound(lisan+1,lisan+k+1,d[i].a) - lisan;
d[i].b = std::lower_bound(lisan+1,lisan+k+1,d[i].b) - lisan;
}
std::sort(d+1,d+n+1);
int ans = -inf;
try(i,1,n)
{
// try(j,1,k) f[i][j] = f[i-1][j];
int temp = t.query(1,1,k,1,std::min(d[i].a,d[i].b)) + d[i].w;
t.modify(1,1,k,d[i].a,temp);
if(d[i].a + 1 <= d[i].b)
t.update(1,1,k,d[i].a+1,d[i].b,d[i].w);
// try(j,1,std::min(d[i].a,d[i].b)) f[i][d[i].a] = std::max(f[i-1][j] + d[i].w,f[i][d[i].a]);
// try(j,d[i].a+1,d[i].b) f[i][j] = f[i-1][j] + d[i].w;
}
// try(i,1,n){try(j,1,k) cout<<f[i][j]<<' '; cout<<endl;}
cout<<t.t[1].s<<endl;
return 0;
}
}
signed main() {return xin::main();}
\(100pts\)
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
#define asm(i,x) for(register signed i=head[x];i;i=edge[i].next)
namespace xin_io
{
#define debug cout<<"debug"<<endl
#define sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
char buf[1<<20],*p1 = buf,*p2 = buf; int ak; typedef long long ll; typedef unsigned long long ull;
class xin_stream{public:template<typename type>inline xin_stream &operator >> (type &x)
{
register type s = 0; register int f = 1; register char ch = gc();
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = gc();}
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return x = s * f,*this;
}}io;
}
#define int long long
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+7; const ll llinf = 1e18+7;
namespace xin
{
class xin_seg
{
private:
#define ls(fa) (fa << 1)
#define rs(fa) (fa << 1 | 1)
inline void up(int fa){t[fa].s = std::max(t[ls(fa)].s ,t[rs(fa)].s);}
inline void down(int fa)
{
if(!t[fa].debt) return;
t[ls(fa)].s += t[fa].debt ; t[rs(fa)].s += t[fa].debt;
t[ls(fa)].debt += t[fa].debt; t[rs(fa)].debt += t[fa].debt;
t[fa].debt = 0;
}
public:
class xin_tree{public:int s,debt;}t[maxn];
void update(int fa,int l,int r,int ql,int qr,int val)
{
if(ql <= l and qr >= r) {t[fa].s += val; t[fa].debt += val; return ;}
register int mid = l + r >> 1;
down(fa);
if(ql <= mid) update(ls(fa),l,mid,ql,qr,val);
if(qr > mid) update(rs(fa),mid+1,r,ql,qr,val);
up(fa);
}
void modify(int fa,int l,int r,int pos,int val)
{
if(l == r) {t[fa].s = std::max(val,t[fa].s); return;}
register int mid = l + r >> 1;
down(fa);
if(pos <= mid) modify(ls(fa),l,mid,pos,val);
else modify(rs(fa),mid+1,r,pos,val);
up(fa);
}
int query(int fa,int l,int r,int ql,int qr)
{
if(ql <= l and qr >= r) return t[fa].s;
register int mid = l + r >> 1,ret = 0;
down(fa);
if(ql <= mid) ret = std::max(ret,query(ls(fa),l,mid,ql,qr));
if(qr > mid) ret = std::max(ret,query(rs(fa),mid+1,r,ql,qr));
return ret;
}
}t;
class xin_data
{
private:
friend bool operator < (xin_data x,xin_data y)
{return (x.a + x.b) < (y.a + y.b);}
public:
int a,b,w;
}d[maxn];
int n;
int lisan[maxn],cnt = 0;
inline short main()
{
io >> n;
try(i,1,n)
{
io >> d[i].a >> d[i].b >> d[i].w;
lisan[++cnt] = d[i].a; lisan[++cnt] = d[i].b;
}
std::sort(lisan+1,lisan+cnt+1);
int k = std::unique(lisan+1,lisan+cnt+1) - (lisan + 1);
try(i,1,n)
{
d[i].a = std::lower_bound(lisan+1,lisan+k+1,d[i].a) - lisan;
d[i].b = std::lower_bound(lisan+1,lisan+k+1,d[i].b) - lisan;
}
std::sort(d+1,d+n+1);
int ans = -inf;
try(i,1,n)
{
// try(j,1,k) f[i][j] = f[i-1][j];
int temp = t.query(1,1,k,1,std::min(d[i].a,d[i].b)) + d[i].w;
t.modify(1,1,k,d[i].a,temp);
if(d[i].a + 1 <= d[i].b)
t.update(1,1,k,d[i].a+1,d[i].b,d[i].w);
// try(j,1,std::min(d[i].a,d[i].b)) f[i][d[i].a] = std::max(f[i-1][j] + d[i].w,f[i][d[i].a]);
// try(j,d[i].a+1,d[i].b) f[i][j] = f[i-1][j] + d[i].w;
}
// try(i,1,n){try(j,1,k) cout<<f[i][j]<<' '; cout<<endl;}
cout<<t.t[1].s<<endl;
return 0;
}
}
signed main() {return xin::main();}
最小距离
考场上 \(\color{green} {AC}\) 的一个题目。
就是我们魔改一下 \(dijkstra\) 然后就可以求出每个非特殊点到特殊点的最近距离。
之后我们还需要记录一下是哪个转移的。
之后枚举每一个边之后统计答案。
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
#define asm(i,x) for(register signed i=head[x];i;i=edge[i].next)
namespace xin_io
{
#define debug cout<<"debug"<<endl
#define sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; int ak; typedef long long ll; typedef unsigned int ull;
class xin_stream{public:template<typename type>inline xin_stream &operator >> (type &x)
{
register type s = 0; register int f = 1; register char ch = gc();
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = gc();}
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return x = s * f,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+7; const ll llinf = 1e18+7;
#define int long long
namespace xin
{
#define mp std::make_pair
class xin_edge{public:int next,ver,w;}edge[maxn];
int head[maxn],zhi = 1;
inline void add(int x,int y,int w) {edge[++zhi].ver = y; edge[zhi].w = w; edge[zhi].next = head[x]; head[x] = zhi;}
std::priority_queue<std::pair<int,int>,std::vector<std::pair<int,int> >,std::greater<std::pair<int,int> > >q;
int dis[maxn],spe[maxn],nre[maxn],ans[maxn];
bool vis[maxn];
int n,m,p;
void dij()
{
while(!q.empty())
{
register int x = q.top().second; q.pop();
if(vis[x]) continue; vis[x] = 1;
asm(i,x)
{
register int y = edge[i].ver,z = edge[i].w;
if(dis[y] > dis[x] + z)
{
dis[y] = dis[x] + z; nre[y] = nre[x];
q.push(mp(dis[y],y));
}
}
}
memset(ans,0x3f,sizeof(int) * (n + 1));
for(register int i=2;i<=zhi;++i,++i)
{
register int y1 = edge[i].ver,y2 = edge[i xor 1].ver;
register int n1 = nre[y1],n2 = nre[y2];
if(n1 xor n2)
{
register int zhuan = dis[y1] + dis[y2] + edge[i].w;
ans[n1] = std::min(ans[n1],zhuan); ans[n2] = std::min(ans[n2],zhuan);
}
}
}
inline short main()
{
io >> n >> m >> p;
memset(dis,0x3f,sizeof(int) * (n + 1));
// cout<<dis[1]<<endl;
try(i,1,p)
{
io >> spe[i];
dis[spe[i]] = 0; q.push(mp(dis[spe[i]],spe[i]));nre[spe[i]] = spe[i];
}
try(i,1,m)
{
register int x,y,z; io >> x >> y >> z;
add(x,y,z); add(y,x,z);
}
dij();
// try(i,1,n) cout<<nre[i]<<' ';cout<<endl;
// try(i,1,n) sb(dis[i]); cout<<endl;
try(i,1,p) printf("%lld ",ans[spe[i]]);
return 0;
}
}
signed main() {return xin::main();}
真相
说简单就是一个大模拟,然而还是很有思维含量的。。
就是如果我们定下来第一个点的真假,那么从地一个人到接下来的一个 '$' 之间就都是可以确定的了。
之后我们就可以尝试枚举每一个这样的相连通的块,之后就可以 \(\mathcal O(n)\) 过掉。
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
#define asm(i,x) for(register signed i=head[x];i;i=edge[i].next)
namespace xin_io
{
#define debug cout<<"debug"<<endl
#define sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define scanf ak = scanf
int ak;
}
using namespace xin_io; static const int maxn = 1e5+10,inf = 1e9+7;
namespace xin
{
class xin_data
{
public:
char s[2];
int num;
}d[maxn];
int n,T;
int num[maxn][2],f[maxn][2],zhi,ton[maxn];
std::vector<int>vec;
inline short main()
{
scanf("%d",&T);
while(T--)
{
zhi = 0;
vec.clear();
scanf("%d",&n);
try(i,1,n)
{
scanf("%s",d[i].s);
if(d[i].s[0] == '$') vec.push_back(i),scanf("%d",&d[i].num);
}
if(!vec.size())
{
register bool now = 1;
try(i,1,n) if(d[i].s[0] == '-') now ^= 1;
puts(now ? "consistent" : "inconsistent");
continue;
}
int sum = 0;
try(i,0,vec.size()-1)
{
register int pos = (vec[i]+1),next,now = 1,cnt = 0,tot = 1;
if(pos > n) pos -= n;
if(i == vec.size() - 1) next = vec[0];
else next = vec[i+1];
for(register int j=pos;j!=next;)
{
if(now) cnt++;
if(d[j].s[0] == '-') now ^= 1;
tot ++; j ++; if(j > n) j -= n;
}
ton[++zhi] = d[next].num;
if(now)
{
cnt++;
num[zhi][0] = cnt; num[zhi][1] = tot - cnt;
}
else
{
num[zhi][0] = tot - cnt;
num[zhi][1] = cnt;
}
f[ton[zhi]][0] += num[zhi][0]; f[ton[zhi]][1] += num[zhi][1];
sum += num[zhi][1];
}
bool ans = 0;
try(i,0,n)
{
int cnt = f[i][0] - f[i][1] + sum;
if(cnt == i) {ans = 1;break;}
}
puts(ans ? "consistent" : "inconsistent");
try(i,1,zhi) f[ton[i]][0] = f[ton[i]][1] = 0;
}
return 0;
}
}
signed main() {return xin::main();}