20261006做题记录
上午模拟赛
T1:
简单贪心。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define N 100005
#define intl long long
#define For(i,a,b) for(intl i=a;i<=b;i++)
#define deo(i,a,b) for(intl i=a;i>=b;i--)
intl read() {
intl x=0,k=1;char ch=getchar();
while(!isdigit(ch)) {if(ch == '-') k=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*k;
}
intl n, k, a[N], vis[N], ans;
int main() {
freopen("peak.in","r",stdin);
freopen("peak.out","w",stdout);
n = read(), k = read();
For(i,1,n) a[i] = read();
For(i,1,n-k+1) {
intl mx = -1, pos = 0, flg = 0;
// For(j,i,i+k-1) if(vis[j]) flg = 1;
For(j,i,i+k-1) if(a[j] >= mx) mx = a[j], pos = j;
For(j,i,i+k-1) if(a[j] == mx && vis[j]) flg = 1;
if(flg) continue;
ans ++, vis[pos] = 1;
}
printf("%lld\n", ans);
return 0;
}
T2:
我们发现,如果我们从大往小处理是可以的,因为如果两个数在 \(M\) 的倍数 \(KM\) 的差值是模数是确定的,那么在 \(M\) 的模数也是确定的,那么我们可以用带权并查集从大到小维护,如果在同一个中就判断合法,没有就加入并更新权值。令 \(dis_u\) 表示 \(u\) 到父亲的距离,那么路径压缩后就是到根的距离,我们令根为 \(0\) 答案是就 \(dis_u\), 输出即可。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define N 200005
#define intl long long
#define For(i,a,b) for(intl i=a;i<=b;i++)
#define deo(i,a,b) for(intl i=a;i>=b;i--)
intl read() {
intl x=0,k=1;char ch=getchar();
while(!isdigit(ch)) {if(ch == '-') k=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*k;
}
struct node{
intl u,v,k,c;
bool operator < (const node&a) const {
return k > a.k;
}
}e[N];
intl n, m, b, dis[N], fa[N], sz[N], mod;
intl get(intl x) {
// cout << x <<endl;
if(x == fa[x]) return x;
intl qwe = fa[x];
fa[x] = get(fa[x]);
(dis[x] += dis[qwe]) %= mod;
return fa[x];
}
intl merge(intl u,intl v,intl k,intl c) {
intl fu = get(u), fv = get(v);
if(fu == fv) return (dis[u]-dis[v]+c)%(1ll<<k);
intl qwe = (dis[u]-dis[v]+c+mod)%mod;
if(sz[fu] >= sz[fv]) fa[fv] = fu, dis[fv] = qwe, sz[fu] += sz[fv];
else fa[fu] = fv, dis[fu] = (-qwe+mod)%mod, sz[fv] += sz[fu];
return 0;
}
void check() {
For(i,1,n) get(i);
For(i,1,m) {
auto [u,v,k,c] = e[i];
if((dis[v] - dis[u] - c)%(1ll<<k)) return puts("NO!!!"), void();
}
}
int main() {
freopen("equation.in","r",stdin);
freopen("equation.out","w",stdout);
n = read(), m = read(), b = read(), mod = (1ll<<b);
For(i,1,n) fa[i] = i, sz[i] = 1;
For(i,1,m) {
intl u = read(), v = read(), k = read(), c = read();
e[i] = {u,v,k,c};
}
sort(e+1,e+m+1);
For(i,1,m) {
auto [u,v,k,c] = e[i];
if(merge(u, v, k, c)) return puts("No"), 0;
}
puts("Yes");
For(i,1,n) get(i), printf("%lld ", dis[i]);
// check();
return 0;
}
T3:
不会。
T4:
不会。
P4912
显然,一个背包,然后就做完了,注意一下它的 \(a_i\) 可以是负的(什么叫做我吟唱的长度是负的,这tm都不是瞬发了,这是负发了。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define N 55
#define intl long long
#define For(i,a,b) for(intl i=a;i<=b;i++)
#define deo(i,a,b) for(intl i=a;i>=b;i--)
intl read() {
intl x=0,k=1;char ch=getchar();
while(!isdigit(ch)) {if(ch == '-') k=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*k;
}
intl w[N][N], a[N], b[N], n, m, dp[N][5005], tp = 2500;
int main() {
memset(dp, 128, sizeof dp);
intl inf = dp[0][0];
dp[0][tp] = 0;
n = read(), m = read();
For(i,1,n) a[i] = read(), b[i] = read();
For(i,1,n) For(j,1,n) w[i][j] = read();
For(i,1,n) For(j,0,i-1) For(k,0,tp+tp)
if(dp[j][k] != inf && k+a[i] >= 0 && k+a[i] <= tp+tp) dp[i][k+a[i]] = max(dp[i][k+a[i]], dp[j][k] + b[i] + w[j][i]);
intl ans = inf;
For(i,1,n) ans = max(ans, dp[i][m+tp]);
printf("%lld\n",ans == inf ? -1ll : ans);
return 0;
}
P2714
简单题,显然,容斥,两种做法:
第一种:
我们令 \(f_i\) 表示 \(\gcd\) 为 \(i\) 的倍数的方案数, \(g_i\) 表示 \(\gcd\) 为 \(i\) 的方案数,那么有 $$f_i = \sum_{i|j} g_j$$ 反演一下, $$g_j = \sum_{j|i} \mu_{\frac{i}{j}} f_i$$ 其中 \(\mu_i\) 为莫比乌斯函数。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define N 10005
#define intl long long
#define For(i,a,b) for(intl i=a;i<=b;i++)
#define deo(i,a,b) for(intl i=a;i>=b;i--)
intl read() {
intl x=0,k=1;char ch=getchar();
while(!isdigit(ch)) {if(ch == '-') k=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*k;
}
intl f[N], mu[N], vis[N], n, cnt[N], a[N], dp[N];
vector<intl> prim;
void init() {
mu[1] = 1;
For(i,2,N-5) {
if(!vis[i]) prim.push_back(i), mu[i] = -1;
for(auto x:prim) {
if(i*x > N-5) break;
vis[i*x] = 1;
if(i%x == 0) break;
mu[i*x] = mu[i]*mu[x];
}
}
For(i,4,N-5) f[i] = i*(i-1)*(i-2)*(i-3)/24;
}
void solve() {
For(i,1,n) a[i] = read(), cnt[a[i]] ++;
intl ans = 0, mx= *max_element(a+1,a+n+1);
For(i,1,mx) {
intl qwe = 0;
for(intl j=i;j<=mx;j += i) qwe += cnt[j];
ans += mu[i]*f[qwe];
}
printf("%lld\n", ans);
}
void clear() {
For(i,1,n) cnt[a[i]] --;
}
int main() {
init();
while(cin >> n) solve(), clear();
return 0;
}
第二种:
令 \(g_i\) 为 \(\gcd\) 恰好为 \(i\) 的方案数,那么 \(g_i = \binom{n}{k} - \sum_{i|j} g_j\) 从大到小做就可以了。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define N 10005
#define intl long long
#define For(i,a,b) for(intl i=a;i<=b;i++)
#define deo(i,a,b) for(intl i=a;i>=b;i--)
intl read() {
intl x=0,k=1;char ch=getchar();
while(!isdigit(ch)) {if(ch == '-') k=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*k;
}
intl f[N], mu[N], vis[N], n, cnt[N], a[N], dp[N];
vector<intl> prim;
void init() {
mu[1] = 1;
For(i,2,N-5) {
if(!vis[i]) prim.push_back(i), mu[i] = -1;
for(auto x:prim) {
if(i*x > N-5) break;
vis[i*x] = 1;
if(i%x == 0) break;
mu[i*x] = mu[i]*mu[x];
}
}
For(i,4,N-5) f[i] = i*(i-1)*(i-2)*(i-3)/24;
}
void solve() {
For(i,1,n) a[i] = read(), cnt[a[i]] ++;
intl ans = 0, mx= *max_element(a+1,a+n+1);
deo(i,mx,1) {
intl qwe = 0;
for(intl j=i;j<=mx;j+=i) dp[i] -= dp[j], qwe += cnt[];
dp[i] += f[qwe];
}
printf("%lld\n", dp[1]);
For(i,1,mx) dp[i] = 0;
}
void clear() {
For(i,1,n) cnt[a[i]] --;
}
int main() {
init();
while(cin >> n) solve(), clear();
return 0;
}

浙公网安备 33010602011771号