[考试总结]noip模拟36
爆炸了。。
\(T1\) 人均 \(80pts\),然后我拿了 \(40pts\)。
然后\(T3\) 有一个暴力可以拿到 \(60pts\) ,然后我 \(8pts\).
然后倒数。。。。。
真TM
在此立下 \(flag\),明天 ak
。。。。。
总之暴力拿满。。。
Dove 打扑克
维护一个 \(ton\),下标就是 \(siz\) 其中放入有多少个大小为 \(siz\) 的元素。
然后就是每次 \(1\) 操作并查集优化,之后维护 \(ton\),发现如果新开一个 \(siz\) 或者是清空一个 \(siz\) 就 \(insert\) 或者是 \(erase\)。
然后查询的时候一个一个扫描 \(set\) 当中的元素。
之后我们发现这个玩意是最多 \(\sqrt n\) 的。
所以总复杂度就是 \(nlogn \sqrt {logn}\)
快的一批。。。
#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
{
int fa[maxn];
inline int find(int x) {return fa[x] == x ? x : fa[x] = find(fa[x]);}
std::set<int>s;
int n,m;
int siz[maxn],ton[maxn];
int a[maxn],zhi = 0;
inline short main()
{
io >> n >> m;
try(i,1,n) fa[i] = i,siz[i] = 1;
s.insert(1); ton[1] = n;
try(que,1,m)
{
register int op; io >> op;
if(op == 1)
{
register int x,y,fx,fy; io >> x >> y;
fx = find(x); fy = find(y);
if(fx == fy) continue;
fa[fx] = fy;
ton[siz[fx]]--; ton[siz[fy]]--;
if(!ton[siz[fx]]) s.erase(siz[fx]);
if(!ton[siz[fy]]) s.erase(siz[fy]);
siz[fy] += siz[fx];
ton[siz[fy]]++;
if(ton[siz[fy]] == 1) s.insert(siz[fy]);
}
else
{
register int c; ll ans = 0,ret = 0; io >> c;zhi = 0;
// for(auto x : s) a[++zhi] = x; a[zhi+1] = inf;
if(!c)
{
int sum = 0;
for(auto x : s) sum += ton[x];
printf("%lld\n",(sum * (sum - 1)) >> 1); continue;
}
for(auto x : s) a[++zhi] = x; a[zhi + 1] = inf;
try(i,1,zhi)
if(a[i] + c > a[zhi]) break;
else
{
int ret = 0;
try(j,i+1,zhi) if(a[i] + c <= a[j]) ret += ton[a[j]];
ans += ret * ton[a[i]];
}
printf("%lld\n",ans);
}
}
return 0;
}
}
signed main() {return xin::main();}
Cicada 与排序
这个我改的是比题解复杂度要高的 \(\mathcal O(n^3)\) 暴力。
采用 \(f_{i,j,k}\) 和 \(g_{i,j}\) 维护。
然后答案就是 \(\sum_{i=1}^{l} \sum_{j=1}^{r} f_{1,i,j}\)
#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 = 5e2+10,inf = 1e9+7; const ll llinf = 1e18+7;
namespace xin
{
const int mod = 998244353;
int temp;
int g[maxn][maxn];
inline int ksm(int x,int y)
{
register int ret =1 ;
while(y)
{
if(y & 1) ret= ret * x % mod;
x = x *x % mod; y >>= 1;
}
return ret;
}
int n,a[maxn];
int f[maxn][maxn][maxn];
void merge_sort(int x,int l,int r)
{
if(l == r) {f[x][l][l] = 1; return ;}
register int mid = l + r >> 1;
merge_sort(x+1,l,mid); merge_sort(x+1,mid+1,r);
memset(g,0,sizeof(g)); g[0][0] = 1;
try(i,0,mid-l+1) try(j,0,r - mid)
{
if(i == mid - l + 1) (g[i][j+1] += g[i][j]) %= mod;
else if(j == r - mid) (g[i+1][j] += g[i][j]) %= mod;
else if(a[i+l] < a[j+mid+1]) (g[i+1][j] += g[i][j]) %= mod;
else if(a[i+l] > a[j+mid+1]) (g[i][j+1] += g[i][j]) %= mod;
else (g[i+1][j] += g[i][j] * temp % mod) %= mod,(g[i][j+1] += g[i][j] * temp % mod) %= mod;
}
try(i,l,r) try(j,0,mid-l+1) try(k,0,r-mid)
{
if(j == mid - l + 1 and k == r - mid) continue;
if(j == mid - l + 1) (f[x][i][j+k+l] += f[x+1][i][k+mid+1] * g[j][k] % mod ) %= mod;
else if(k == r - mid) (f[x][i][j+k+l] += f[x+1][i][j+l] * g[j][k] % mod) %= mod;
else if(a[j+l] < a[k+mid+1]) (f[x][i][j+k+l] += f[x+1][i][j+l] * g[j][k] % mod) %= mod;
else if(a[j+l] > a[k+mid+1]) (f[x][i][j+k+l] += f[x+1][i][k+mid+1] * g[j][k] % mod) %= mod;
else (f[x][i][j+k+l] += f[x+1][i][j+l] * g[j][k] % mod * temp % mod) %= mod,
(f[x][i][j+k+l] += f[x+1][i][k+mid+1] * g[j][k] % mod * temp % mod) %= mod;
}
std::sort(a+l,a+r+1);
}
inline short main()
{
io >> n; try(i,1,n) io >> a[i];
temp = ksm(2,mod-2);
merge_sort(1,1,n);
try(i,1,n)
{
register int ans = 0;
try(j,1,n)
(ans += f[1][i][j] * j % mod) %= mod;
printf("%lld ",ans);
}
return 0;
}
}
signed main() {return xin::main();}
Cicada 拿衣服
一眼上去感觉线段树,然后并没有多少分。。
其实 \(n^2\) 暴力就有很多很多。
就是先固定一个 \(l\),然后狂扫 \(r\),之后再去改变调整。
\(64pts\)
#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
{
int a[maxn],k,n,ans[maxn];
inline short main()
{
io >> n >> k;
try(i,1,n) io >> a[i];
try(i,1,n)
{
register int l = i,maxx = a[i],minn = a[i],ret1 = a[i],ret2 = a[i],temp,maxr = -llinf;
try(r,i+1,n)
{
maxx = std::max(maxx,a[r]);
minn = std::min(minn,a[r]);
ret1 |= a[r]; ret2 &= a[r];
temp = minn + ret1 - maxx - ret2;
if(temp >= k) maxr = r;
}
if(maxr == -llinf)
{
if(!ans[i]) ans[i] = -1;
continue;
}
try(j,i,maxr) ans[j] = std::max(ans[j],maxr - l + 1);
}
try(i,1,n) printf("%lld ",ans[i]);
return 0;
}
}
signed main() {return xin::main();}
然后我是没脸搞过去的。。。
其实并不用跑满,其实整个函数的变化大概是一个单峰函数。
然后及时停止就有很多分。。
#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
{
int a[maxn],k,n,ans[maxn];
inline short main()
{
io >> n >> k;
try(i,1,n) io >> a[i];
try(i,1,n)
{
register int l = i,maxx = a[i],minn = a[i],ret1 = a[i],ret2 = a[i],temp,maxr = -llinf;
try(r,i+1,n)
{
maxx = std::max(maxx,a[r]);
minn = std::min(minn,a[r]);
ret1 |= a[r]; ret2 &= a[r];
temp = minn + ret1 - maxx - ret2;
if(n >= 40000 and r - l + 1 >= 698) break;
if(temp >= k) maxr = r;
}
if(maxr == -llinf)
{
if(!ans[i]) ans[i] = -1;
continue;
}
try(j,i,maxr) ans[j] = std::max(ans[j],maxr - l + 1);
}
try(i,1,n) printf("%lld ",ans[i]);
return 0;
}
}
signed main() {return xin::main();}