[考试总结]noip模拟30
二维 XIN 队算法打挂。。。
然后只剩下完蛋的 \(15pts\)。。。
然后 \(T2\) 莽了一个 \(\mathcal O(n!)\) 的完蛋全排列。。
然后 \(20pts\)
然而 \(T3\) 救我于水火之中。。。
本来对着 \(40pts\) 的部分分数,然后奇迹 \(A\) 掉。。
发现其实常数极小。。。
开心。。。
毛一琛
这到题目就是之前一直也说过的 \(meet\;in\;middle\) 优化 XIN 算法。
然后我们就会对复杂度开根。
就是 \(\mathcal O(3^{\frac{n}{2}})\)
飞快。
其实可以跑将近 \(40\) 的数据。
有童鞋可能对复杂度有疑问。
实际上就是对于每一种数字有 \(3\) 中状态: 不选,在第一集合,在第二集合
然后就没了。。
#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 enum(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 = (1 << 20) + 1,inf = 1e9+7,mod = 998244353; const ll llinf = 1e18+7;
namespace xin
{
int w[maxn],n,ans = 0,tot;
// int a;
std::unordered_map<int,int>mp;
std::vector<int>vec[maxn];
bool vis[maxn];
int mid;
void dfs1(int now,int rmb1,int rmb2,int a)
{
if(now == mid + 1)
{
int temp = abs(rmb1 - rmb2);
if(!mp[temp]) mp[temp] = ++tot;
int zhuan = mp[temp];
vec[zhuan].push_back(a);
return ;
}
dfs1(now+1,rmb1,rmb2,a);
dfs1(now+1,rmb1+w[now],rmb2,a | (1 << (now - 1)));
dfs1(now+1,rmb1,rmb2+w[now],a | (1 << (now - 1)));
}
void dfs2(int now,int rmb1,int rmb2,int a)
{
if(now == n + 1)
{
int temp = abs(rmb1 - rmb2);
if(!mp[temp]) return ;
int zhuan = mp[temp];
try(i,0,vec[zhuan].size() - 1)
vis[(a << mid) | vec[zhuan][i]] = 1;
return ;
}
dfs2(now+1,rmb1,rmb2,a);
dfs2(now+1,rmb1+w[now],rmb2,a | (1 << ((now - mid) - 1)));
dfs2(now+1,rmb1,rmb2+w[now],a | (1 << ((now - mid) - 1)));
}
inline short main()
{
io >> n; try(i,1,n) io >> w[i];//,enum(w[i]);
mid = n >> 1;
dfs1(1,0,0,0); dfs2(mid+1,0,0,0);
try(i,0,(1 << n)-1)
ans += vis[i];
cout<<ans-1<<endl;
return 0;
}
}
signed main() {return xin::main();}
毛二琛
这个题目还是比较难的的。
我考场上的暴力还是朴素的 \(next_permutation\),然后 \(\mathcal O(n!)\) 复杂度。
然后拿到场均的 \(20pts\) 高分。。
正解是 \(dp\)
我们用一个 \(zhuan\) 数组来记录这个数字要转移到的位置。
之后 \(f_{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)
#define int long long
namespace xin_io
{
#define enum(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 = 5e3+10,inf = 1e9+7,mod = 1e9+7; const ll llinf = 1e18+7;
namespace xin
{
int zhuan[maxn],a[maxn];
int n,ans;
int g[maxn][maxn],f[maxn][maxn];
inline short main()
{
io >> n;
try(i,0,n-1) io >> a[i];
try(i,0,n-1)
if(i < a[i]) zhuan[i-1] = 1,zhuan[a[i] - 1] = 1;
else try(j,a[i],i-2) zhuan[j] = 1;
f[0][1] = g[0][1] = 1;
try(i,1,n-2) try(j,1,i+1)
{
if(zhuan[i-1]) (f[i][j] += g[i-1][i] - g[i-1][j-1] + mod) %= mod;
else (f[i][j] += g[i-1][j-1]) %= mod;
(g[i][j] = g[i][j-1] + f[i][j]) %= mod;
}
try(i,0,n-1) (ans += f[n-2][i]) %= mod;
cout<<ans % mod<<endl;
return 0;
}
}
signed main() {return xin::main();}
毛三琛
这个题目实际上就是我们想的 \(\mathcal O(n^2logn)\) 的复杂度就能过的题目。
你可能不信,我也不信,然而就是过了。。
#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 enum(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 n,mod,k;
int a[maxn],b[maxn];
int ans = inf;
inline bool check(int x)
{
register int res = 0,sum = 0;
try(i,1,n)
{
if(b[i] > x)return false;
if(res + b[i] > x) res=0,sum++;
res += b[i];
}
return sum < k;
}
int p[maxn];
inline short main()
{
srand(unsigned(time(0)) xor clock());
io >> n >> mod >> k;
try(i,1,n) io >> a[i],p[i] = i;
std::random_shuffle(p+1,p+n+1);
try(i,0,mod-1)
{
register int l=0,r=0,res = inf,temp;
try(j,1,n)
{
b[j] = (a[j] + p[i]) % mod;
r += b[j];
}
if(!check(ans)) continue;
while(l <= r)
{
register int mid = l + r >> 1;
if(check(mid)) res=mid,r=mid-1;
else l = mid+1;
}
ans = std::min(ans,res);
}
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}