Educational Codeforces Round 20
A. Maximal Binary Matrix
直接从上到下从左到右填,注意只剩一个要填的位置的情况
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 111;
bool vis[MAXN][MAXN];
void solve(){
int n, k; cin >> n >> k;
if(n*n<k) cout << -1 << endl;
else{
for(int i = 1; i <= n and k; i++) for(int j = 1; j <= n and k; j++){
if(vis[i][j]) continue;
if(k==1){
if(i!=j) continue;
vis[i][j] = true;
k--; break;
}
vis[i][j] = vis[j][i] = true;
if(i==j) k -= 1;
else k -= 2;
if(!k) break;
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++) cout << (vis[i][j] ? 1 : 0) << ' ';
cout << endl;
}
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("Local.in","r",stdin);
freopen("ans.out","w",stdout);
#endif
solve();
return 0;
}
B. Distances to Zero
把所有\(0\)的位置记下来然后二分找最近位置即可
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2e5+7;
void solve(){
____();
int n;
cin >> n;
vector<int> vec(n);
for(int &x : vec) cin >> x;
vector<int> zeropos;
for(int i = 0; i < n; i++) if(!vec[i]) zeropos.push_back(i);
for(int i = 0; i < n; i++){
auto p = lower_bound(zeropos.begin(),zeropos.end(),i);
int ret = MAXN;
if(p!=zeropos.end()) ret = *p - i;
if(p!=zeropos.begin()){
p--;
ret = min(ret,i-*p);
}
cout << ret << ' ';
}cout << endl;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("Local.in","r",stdin);
freopen("ans.out","w",stdout);
#endif
solve();
return 0;
}
C. Maximal GCD
考虑枚举\(g=gcd(A)\),由于要递增,所以填的方式为\(g,2g,3g,\cdots kg+l\)
显然要满足\(g\mid \sum A_i\),找最大的满足条件的\(g\)即可
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
typedef long long int LL;
void solve(){
LL n, k;
cin >> n >> k;
if(k>1e7 or (k+1)*k/2>n) cout << -1 << endl;
else{
vector<LL> f;
for(LL i = 1; i * i <= n; i++){
if(n%i) continue;
f.push_back(i);
if(i!=n/i) f.push_back(n/i);
}
sort(f.begin(),f.end());
LL tot = (k + 1) * k / 2;
LL g = 1;
for(auto d : f){
if(tot * d > n) break;
g = max(g,d);
}
vector<LL> ret;
for(int i = 0; i < k; i++){
ret.push_back((i+1)*g);
n -= (i+1)*g;
}
ret.back() += n;
for(auto x : ret) cout << x << ' ';
cout << endl;
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("Local.in","r",stdin);
freopen("ans.out","w",stdout);
#endif
solve();
return 0;
}
D.Magazine Ad
把所有串按空格和横杠分开,得到一些短的串,每个串的权值为长度,问题转化为把\(n\)个数分成最多\(k\)组,求权值最大的组的最小值,二分即可
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1e6+7;
int k;
void solve(){
____();
string s;
cin >> k;
cin.get(); getline(cin,s);
s.push_back('-');
// binary search
vector<int> pos;
pos.push_back(-1);
for(int i = 0; i < s.length(); i++) if(s[i]=='-' or s[i]==' ') pos.push_back(i);
vector<int> seg;
for(int i = 1; i < pos.size(); i++) seg.push_back(pos[i] - pos[i-1]);
seg.back()--;
auto check = [&](int m){
int cnt = 0, tot = 0;
for(int i = 0; i < seg.size(); i++){
if(seg[i]>m) return false;
if(tot + seg[i] <= m) tot += seg[i];
else{
cnt++;
tot = seg[i];
}
}
cnt++;
return cnt <= k;
};
int l = 1, r = s.length();
while(l<=r){
int mid = (l + r) >> 1;
if(check(mid)) r = mid - 1;
else l = mid + 1;
}
cout << l << endl;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("Local.in","r",stdin);
freopen("ans.out","w",stdout);
#endif
solve();
return 0;
}
E. Roma and Poker
考虑\(DP\),\(dp[i][j]\)表示到第\(i\)个位置赢和输的差值为\(j\)的情况下的上一个状态
转移的时候注意不能从差值的绝对值为\(k\)的状态转移过来
最后倒推回去输出答案就好了
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1e3+7;
const int D = 1e3+3;
const int INF = 0x3f3f3f3f;
int f[MAXN][MAXN<<1];
int n, k;
char s[MAXN];
void solve(){
____();
cin >> n >> k >> s + 1;
memset(f,0x3f,sizeof(f));
f[0][D] = -1;
for(int i = 1; i <= n; i++){
if(s[i]=='L' or s[i]=='?'){ // lose
for(int j = D - k + 1; j <= D + k - 1; j++){
if(f[i-1][j]==INF) continue;
f[i][j-1] = j;
}
}
if(s[i]=='W' or s[i]=='?'){ // win
for(int j = D - k + 1; j <= D + k - 1; j++){
if(f[i-1][j]==INF) continue;
f[i][j+1] = j;
}
}
if(s[i]=='D' or s[i]=='?'){
for(int j = D - k + 1; j <= D + k - 1; j++){
if(f[i-1][j]==INF) continue;
f[i][j] = j;
}
}
}
if(f[n][D+k]==INF and f[n][D-k]==INF) cout << "NO" << endl;
else{
int u;
string ret;
if(f[n][D+k]!=INF) u = D + k;
else u = D - k;
for(int i = n; i >= 1; i--){
if(u - f[i][u] == 0) ret.push_back('D');
else if(u - f[i][u] == 1) ret.push_back('W');
else ret.push_back('L');
u = f[i][u];
}
reverse(ret.begin(),ret.end());
cout << ret << endl;
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("Local.in","r",stdin);
freopen("ans.out","w",stdout);
#endif
solve();
return 0;
}
F. Coprime Subsequences
\(f(n)\)表示组合的\(gcd=n\)的方案数
\(F(n)\)表示组合的\(n\mid gcd\)的方案数
那么\(F(n) = \sum_{n\mid d}f(d)\)
根据莫比乌斯反演,\(f(n) = \sum_{n\mid d}\mu(\frac dn)F(d)\)
我们要求的答案就是\(f(1)\)
容易发现如果有\(x\)个数的因子有\(d\)那么\(F(d) = 2^x-1\)
那么我们就能很容易算出\(f(1)\)了
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MOD = 1e9+7;
const int MAXN = 1e5+7;
int n, prime[MAXN], pri_cnt, mu[MAXN], cnt[MAXN], pw[MAXN];
bool npm[MAXN];
vector<int> ds[MAXN];
void sieve(){
mu[1] = 1;
for(int i = 2; i < MAXN; i++){
if(!npm[i]) prime[++pri_cnt] = i, mu[i] = -1;
for(int j = 1; i * prime[j] < MAXN; j++){
npm[i*prime[j]] = true;
if(i%prime[j]==0){
mu[i*prime[j]] = 0;
break;
}
mu[i*prime[j]] = -mu[i];
}
}
for(int i = 1; i < MAXN; i++) for(int j = i; j < MAXN; j += i) ds[j].push_back(i);
pw[0] = 1;
for(int i = 1; i < MAXN; i++) pw[i] = pw[i-1] * 2 % MOD;
}
void solve(){
____();
sieve();
cin >> n;
for(int i = 1; i <= n; i++){
int x; cin >> x;
for(int d : ds[x]) cnt[d]++;
}
int ret = 0;
for(int i = 1; i < MAXN; i++) ret = (ret + mu[i] * 1ll * (pw[cnt[i]] - 1)) % MOD;
cout << (ret + MOD) % MOD << endl;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("Local.in","r",stdin);
freopen("ans.out","w",stdout);
#endif
solve();
return 0;
}
G. Periodic RMQ Problem
由于范围比较大,考虑离散化坐标,为了能找到最小值,需要在离散化坐标相邻的两点中间额外加入一个区间最小值的点,这个点的值可以用\(ST\)表来找,加的点的值根据两点实际坐标的距离和位置稍微分类一下就好了,然后就很好搞了
view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 6e5 + 7;
const int INF = 0x3f3f3f3f;
int n, k, A[MAXN][20];
struct Qs{ int type, l, r, x; }Q[MAXN];
struct SegTree{
#define ls(rt) rt << 1
#define rs(rt) rt << 1 | 1
int minn[MAXN<<2], l[MAXN<<2], r[MAXN<<2], lazy[MAXN<<2];
#define pushup(rt) minn[rt] = min(minn[ls(rt)],minn[rs(rt)])
void build(int L, int R, vector<pair<int,int> > &vcc, int rt = 1){
l[rt] = L, r[rt] = R;
if(L + 1 == R){
minn[rt] = vcc[L].second;
return;
}
int mid = (L + R) >> 1;
build(L,mid,vcc,ls(rt)); build(mid,R,vcc,rs(rt));
pushup(rt);
}
void pushdown(int rt){
if(!lazy[rt]) return;
lazy[ls(rt)] = lazy[rs(rt)] = minn[ls(rt)] = minn[rs(rt)] = lazy[rt];
lazy[rt] = 0;
}
void modify(int L, int R, int x, int rt = 1){
if(L>=r[rt] or l[rt]>=R) return;
if(L<=l[rt] and r[rt]<=R){
lazy[rt] = minn[rt] = x;
return;
}
pushdown(rt);
modify(L,R,x,ls(rt)); modify(L,R,x,rs(rt));
pushup(rt);
}
int query(int L, int R, int rt = 1){
if(L>=r[rt] or l[rt]>=R) return INF;
if(L<=l[rt] and r[rt]<=R) return minn[rt];
pushdown(rt);
return min(query(L,R,ls(rt)),query(L,R,rs(rt)));
}
}ST;
void solve(){
____();
cin >> n >> k;
for(int i = 0; i < n; i++) cin >> A[i][0], A[i+n][0] = A[i][0];
for(int j = 1; (1 << j) <= (n << 1); j++) for(int i = 0; i + (1 << j) - 1 < (n << 1); i++) A[i][j] = min(A[i][j-1],A[i+(1<<(j-1))][j-1]);
auto query = [&](int l, int r){
int d = (int)log2(r - l + 1);
return min(A[l][d],A[r-(1<<d)+1][d]);
};
int q; cin >> q;
vector<int> vec;
for(int i = 0; i < q; i++){
cin >> Q[i].type >> Q[i].l >> Q[i].r;
Q[i].l--; Q[i].r--;
if(Q[i].type==1) cin >> Q[i].x;
vec.push_back(Q[i].l); vec.push_back(Q[i].r);
}
sort(vec.begin(),vec.end());
vec.erase(unique(vec.begin(),vec.end()),vec.end());
vector<pair<int,int> > vcc;
for(int i = 1, lim = vec.size(); i < lim; i++){
if(vec[i]==vec[i-1]+1) continue;
if(vec[i]-vec[i-1]+1>=n) vcc.push_back({vec[i-1]+1,query(0,n-1)});
else{
int l = vec[i-1] % n, r = vec[i] % n;
if(l>r) r += n;
vcc.push_back({vec[i-1]+1,query(l+1,r-1)});
}
}
for(int i = 0; i < (int) vec.size(); i++) vcc.push_back({vec[i],A[vec[i]%n][0]});
sort(vcc.begin(),vcc.end());
ST.build(0,vcc.size(),vcc);
for(int i = 0; i < q; i++){
int l = Q[i].l, r = Q[i].r;
l = lower_bound(vcc.begin(),vcc.end(),make_pair(l,0)) - vcc.begin();
r = lower_bound(vcc.begin(),vcc.end(),make_pair(r,0)) - vcc.begin();
if(Q[i].type==1) ST.modify(l,r+1,Q[i].x);
else printf("%d\n",ST.query(l,r+1));
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("Local.in","r",stdin);
freopen("ans.out","w",stdout);
#endif
solve();
return 0;
}