[考试总结]noip模拟43
这个题目出的还是很偷懒。。。。
第一题。。。第二题。。。第三题。。。四。。。。
好吧。。。
这几次考得都有些问题,似乎可能是有些疲惫,脑袋也是转不太动,考完总觉得自己是能力的问题,但是改一分钟之后会发现自己硬生生把正解干成了暴力。
第一题
这个题目一眼看上去是一个很不错的贪心题目。
之后我们确实可以使用贪心来做这个题目。
其实就是我们发现一定会是先走到小的里面,然后再去折到上面。
然后其实这个题目还是可以使用 \(dp\) 来做,可是我似乎是不会。。。
#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 sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define debug cout<<"debug"<<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 &s)
{
register int f = 0;s = 0; register char ch = gc();
while(!isdigit(ch)) {f |= ch == '-'; ch = gc();}
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+7; const ll llinf = 1e18+7;
namespace xin
{
class xin_edge{public:int next,ver;}edge[maxn];
int head[maxn],zhi = 0;
inline void add(int x,int y) {edge[++zhi].ver = y; edge[zhi].next = head[x]; head[x] = zhi;}
int n,ind[maxn];
int d[maxn],maxd[maxn];
int sum[maxn],val[maxn];
class xin_data
{
private:
friend bool operator < (xin_data x,xin_data y)
{return x.maxd < y.maxd;}
public:
int x,maxd;
xin_data(){}
xin_data(int x,int maxd):x(x),maxd(maxd){}
};
void dfs1(int x,int f)
{
d[x] = d[f] + 1; maxd[x] = d[x];
asm(i,x)
{
register int y = edge[i].ver;
if(y == f) continue;
dfs1(y,x);
maxd[x] = std::max(maxd[x],maxd[y]);
}
}
void dfs2(int x,int f)
{
std::vector < xin_data > vec; vec.clear();
asm(i,x)
{
register int y = edge[i].ver;
if(y == f) continue;
dfs2(y,x);
vec.push_back(xin_data(y,maxd[y]));
val[x] += sum[y];
}
std::sort(vec.begin(),vec.end());
try(i,0,(int)vec.size() - 1)
{
if(i and vec[i-1].maxd - d[x] < d[x]) sum[x]--,val[x] += vec[i-1].maxd - d[x];
sum[x] += sum[vec[i].x]; val[x] += val[vec[i].x];
}
}
inline short main()
{
io >> n;
try(i,1,n-1)
{
register int x,y; io >> x >> y;
add(x,y); add(y,x); ind[x] ++; ind[y] ++;
}
dfs1(1,0);
try(i,1,n) if(ind[i] == 1) sum[i] = 1;
dfs2(1,0);
cout<<val[1]<<endl;
return 0;
}
}
signed main() {return xin::main();}
第二题
似乎好像是用 \(dij\) 或者是 \(spfa\),但是我使用了 \(nb\) 方法过了。
我们有一个很 \(naive\) 的想法就是二分答案,之后每一个格子这样 \(\mathcal O(nm)\) 的去找,然后把小的那个加上需要的差值。
然后我们就很容易发现这个做法是个假的。
但是。
进行的每一次 \(\mathcal O(nm)\) 扫描,其实都是一次修正性算法。
所以每一次进行这个算法,都会更加正确。
所以我们只需要多做几次,也就是增加几个常数,然后就可以顺利过掉这个题目。
#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 sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define debug cout<<"debug"<<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 &s)
{
register int f = 0;s = 0; register char ch = gc();
while(!isdigit(ch)) {f |= ch == '-'; ch = gc();}
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*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
{
#define abs(x) (x < 0 ? -x : x)
int n,m,k;
int a[maxn/200][maxn/200],b[maxn/200][maxn/200];
inline bool check(int x)
{
register int temp = k;
try(i,1,n) try(j,1,m) b[i][j] = a[i][j];
try(cse,1,14)
try(i,1,n) try(j,1,m)
{
if(j - 1 >= 1) //(i,j-1)
{
register int cha = b[i][j] - b[i][j-1];
if(abs(cha) > x)
{
temp -= abs(cha) - x;
if(cha < 0) b[i][j] += abs(cha) - x;
else b[i][j-1] += abs(cha) - x;
}
}
if(j + 1 <= m) //(i,j+1)
{
register int cha = b[i][j] - b[i][j+1];
if(abs(cha) > x)
{
temp -= abs(cha) - x;
if(cha < 0) b[i][j] += abs(cha) - x;
else b[i][j+1] += abs(cha) - x;
}
}
if(i + 1 <= n and j - 1 >= 1) //(i+1,j-1)
{
register int cha = b[i][j] - b[i+1][j-1];
if(abs(cha) > x)
{
temp -= abs(cha) - x;
if(cha < 0) b[i][j] += abs(cha) - x;
else b[i+1][j-1] += abs(cha) - x;
}
}
if(i - 1 >= 1) //(i-1,j)
{
register int cha = b[i][j] - b[i-1][j];
if(abs(cha) > x)
{
temp -= abs(cha) - x;
if(cha < 0) b[i][j] += abs(cha) - x;
else b[i-1][j] += abs(cha) - x;
}
}
if(i -1 >= 1 and j + 1 <= m) //(i-1,j+1)
{
register int cha = b[i][j] - b[i-1][j+1];
if(abs(cha) > x)
{
temp -= abs(cha) - x;
if(cha < 0) b[i][j] += abs(cha) - x;
else b[i-1][j+1] += abs(cha) - x;
}
}
if(i + 1 <= n) //(i+1,j)
{
register int cha = b[i][j] - b[i+1][j];
if(abs(cha) > x)
{
temp -= abs(cha) - x;
if(cha < 0) b[i][j] += abs(cha) - x;
else b[i+1][j] += abs(cha) - x;
}
}
}
return temp >= 0;
}
int maxx = -inf;
inline short main()
{
io >> n >> m >>k ;
try(i,1,n) try(j,1,m) io >> a[i][j],maxx = std::max(a[i][j],maxx);
register int l = 0,r = maxx;
while(l != r - 1 and l < r)
{
register int mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid;
}
if(check(l)) cout<<l<<endl;
else cout<<r<<endl;
return 0;
}
}
signed main() {return xin::main();}
第三题
一个 \(10\) 分暴力滚粗了。。。。
第四题
一个很强的 \(dp\),到现在还是不是很理解。。。
#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 sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define debug cout<<"debug"<<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 &s)
{
register int f = 0;s = 0; register char ch = gc();
while(!isdigit(ch)) {f |= ch == '-'; ch = gc();}
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*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 fmod(x) (x -= (x >= mod) ? mod : 0)
int ans = 0;
int f[maxn/300][maxn/300],g[maxn/300][maxn/300];
int n,mod;
int sum[maxn/300][maxn/300];
inline short main()
{
io >> n >> mod; f[0][0] = 1;
try(i,1,n) try(j,1,n) f[i][j] = (f[i-1][j-1] + f[i-1][j] * j % mod),fmod(f[i][j]);
try(i,1,n) g[0][i] = 1;
try(i,1,n) try(j,1,n) g[i][j] = (g[i-1][j+1] + g[i-1][j] * j % mod),fmod(g[i][j]);
try(i,1,n) throw(j,n,1)
{
sum[i][j] = f[i-1][j] * (g[n-i][j] + 2 * (n - i * 1ll) * g[n-i-1][j] % mod) % mod;
sum[i][j] += sum[i][j+1]; fmod(sum[i][j]);
}
try(x,1,n)
{
register int ans = 0;
try(i,1,n)
{
register int temp = sum[i][x];
(temp += f[i-1][x-1] * (g[n-i][x] + 2 * (n - i * 1ll) * g[n-i-1][x] % mod) % mod); fmod(temp);
(ans += temp); fmod(ans);
}
printf("%lld ",ans);
}
return 0;
}
}
signed main() {return xin::main();}