赛中3题,第四题想了个七七八八,但是还是差一点,最后膜了题解,赛后写过去的qwq。
没啥罚时,海星,不过T3的ST表写的很痛苦,感觉得多打打ST表板子了,这个推了我好一会。
C题:
分三种情况 4的倍数 2的倍数但不是4的倍数 奇数。
第二种显然打堆处理,可以整体看做一个奇数(如果有的话)
然后判一判。
#include<bits/stdc++.h>
using namespace std;
int n, m;
int val;
int cnt1, cnt2, cnt4;
int main() {
scanf("%d", &n);
for(int i=1;i<=n;++i) {
scanf("%d", &val);
if(val % 4 == 0)
cnt4++;
else if(val % 2 == 0)
cnt2++;
else
cnt1++;
}
if(cnt2)
cnt1++;
printf(cnt4 - cnt1 >= -1 ? "Yes" : "No");
return 0;
}
D题:
给格子蛇形编个号,顺着涂就完事。
#include<bits/stdc++.h>
using namespace std;
int mp[120][120];
int x[10010], y[10010];
int h, w, n;
int a[10010], mcnt, pcnt;
int main() {
scanf("%d%d", &h, &w);
for(int i=1;i<=h;++i) {
if(i % 2)
for(int j=1;j<=w;++j)
++mcnt, x[mcnt] = i, y[mcnt] = j;
else
for(int j=w;j>=1;--j)
++mcnt, x[mcnt] = i, y[mcnt] = j;
}
scanf("%d", &n);
for(int i=1;i<=n;++i) {
scanf("%d", &a[i]);
for(int t=1;t<=a[i];++t) {
pcnt++;
mp[x[pcnt]][y[pcnt]] = i;
}
}
for(int i=1;i<=h;++i) {
for(int j=1;j<=w;++j) {
printf("%d ",mp[i][j]);
}
printf("\n");
}
return 0;
}
E题:
好题。
字典序直接指向无脑贪心。
相邻且往后放,转化一下,变成任取往前放。
对于区间
[
l
,
r
]
[l, r]
[l,r],贪心的找从里面拿出的合法的字典序最小的pair是个啥。由于字典序最小,那么先第一位最小,然后第二位。
发觉左边是距离
l
l
l为偶数的下标的最小值,右边元素是在左边元素右边,距离
l
l
l为奇数下标的最小值。
下标奇偶限制是手玩出来的www,不然会发觉左边剩了奇数个元素,在原问题就没啥救。
然后变为区间奇偶下标查最值——俩st表。
查出来之后,本来想的是挂个三叉树,然后跑树上最小字典序的拓扑序,后来发觉我直接摸个堆出来就完事。
主要是ST表那里调了好一会,感觉对这东西确实不太熟。
(诶不过我脑补的ST表居然过了,就很开心.jpg)
#include<bits/stdc++.h>
using namespace std;
int stj[200010][20];
int sto[200010][20];
int lo[200010];
int mp[200010];
int pw[210];
int a[200010];
int n;
struct info {
int x, y;
int lpos, rpos;
int l, r;
bool operator < (const info &a) const {
return x > a.x;
}
};
priority_queue<info>sth;
void init() {
pw[0] = 1;
for(int i=1;i<=100;++i)
pw[i] = pw[i-1] * 2;
for(int i=1;i<=n;++i) {
for(int j=0;j<=20;++j) {
if(pw[j] > i) {
lo[i] = j-1;
break;
}
}
}
for(int i=1;i<=n;++i) {
if(i % 2)
stj[i][0] = a[i], sto[i][0] = 0x3f3f3f3f;
else
sto[i][0] = a[i], stj[i][0] = 0x3f3f3f3f;
}
for(int T=1;T<=19;++T) {
for(int i=1;i<=n;++i) {
int lef = i, rig = i + pw[T] - 1;
int haf = i + pw[T-1];
if(haf > n) {
sto[i][T] = sto[i][T-1];
stj[i][T] = stj[i][T-1];
}
else {
sto[i][T] = min(sto[i][T-1], sto[haf][T-1]);
stj[i][T] = min(stj[i][T-1], stj[haf][T-1]);
}
}
}
return;
}
int query(int l, int r, bool type) {
//type = 0 sto type = 1 stj
int len = r - l + 1;
int T = lo[len];
int haf = r - pw[T] + 1;
if(type == 1)
return min(stj[l][T], stj[haf][T]);
else
return min(sto[l][T], sto[haf][T]);
}
info getpac(int l, int r) {
if(r < l)
return {0, 0, 0, 0, 0, 0};
int ltar, rtar, lpos, rpos;
if(l % 2 == 1) {
ltar = query(l, r, 1);
lpos = mp[ltar];
rtar = query(lpos+1, r, 0);
rpos = mp[rtar];
}
else {
ltar = query(l, r, 0);
lpos = mp[ltar];
rtar = query(lpos+1, r, 1);
rpos = mp[rtar];
}
return (info){ltar, rtar, lpos, rpos, l, r};
}
void split(info a) {
int l = a.l, r = a.r, lpos = a.lpos, rpos = a.rpos;
info nw;
if(l < lpos-1) {
nw = getpac(l, lpos-1);
sth.push(nw);
}
if(lpos+1 < rpos-1) {
nw = getpac(lpos+1, rpos-1);
sth.push(nw);
}
if(rpos+1 < r) {
nw = getpac(rpos+1, r);
sth.push(nw);
}
return;
}
int main() {
scanf("%d", &n);
for(int i=1;i<=n;++i)
scanf("%d", &a[i]), mp[a[i]] = i;
init();
sth.push(getpac(1, n));
while(!sth.empty()) {
info nw = sth.top(); sth.pop();
printf("%d %d ", nw.x, nw.y);
split(nw);
}
return 0;
}
F题:
首先看到区间反转,无脑转差分。
转了之后变成两点的翻转,且距离为奇质数。
然后是,如果俩数正好差一个奇质数,那么贡献为1,这里可以筛个质数然后跑二分图匹配。
然后就卡这儿了,卡了几分钟,后去膜了发题解。
题解爸爸告诉我,差偶数的话,差2可以5-3,差4可以7-3,差更多可以 哥 德 巴 赫 猜 想
谁没事想得起这玩意啊!
然后差奇数就可以变偶数 - 奇质数了,贡献3。
跑二分图匹配,剩下的贪一下。
哦对,注意二分图匹配的时候,与S相连的边和与T相连的边一定只能连单向边。要是偷懒,连双向,就会GG。
我也不知道他咋GG的,但是我G了。
dinic是贴的板。
#include<bits/stdc++.h>
using namespace std;
bool vis[10000040];
int prime[2000010];
int x[1010], y[1010];
int n, m;
const int maxn = 10000010;
int prcnt;
namespace Maxflow {
struct edge {
int to,flow,op;
}; vector<edge>ed[10010];
int ly[10010],cur[10010]; queue<int>sth;
int SS, TT, pcnt;
inline void ade(int l,int r,int f) {
ed[l].push_back({r,f, (int)ed[r].size()});
ed[r].push_back({l,0, (int)ed[l].size() - 1});
}
inline bool bfs(int S, int T) {
memset(cur,0,sizeof(cur)),memset(ly,0,sizeof(ly)), ly[S] = 1, sth.push(S);
while(!sth.empty()) { int nw = sth.front(); sth.pop();
for(int i=0;i<ed[nw].size();++i) {
int tar = ed[nw][i].to;
if(ed[nw][i].flow == 0 || ly[tar]) continue;
ly[tar] = ly[nw] + 1, sth.push(tar);
}
} return ly[T] != 0;
}
inline int dfs(int nw, int ftar, int nflow) {
if(nw == ftar) return nflow;
int ret = 0;
for(int i=cur[nw];i<ed[nw].size();++i) { cur[nw] = i;
int tar = ed[nw][i].to;
if(ly[tar] != ly[nw] + 1) continue;
int ncanf = dfs(tar, ftar, min(nflow - ret, ed[nw][i].flow));
ed[nw][i].flow -= ncanf, ed[tar][ed[nw][i].op].flow += ncanf;
ret += ncanf; if(ret == nflow) break;
} return ret;
}
inline long long dinic(int S, int T) { long long ret = 0;
while(bfs(S,T))
ret += dfs(S,T,0x3f3f3f3f);
return ret;
}
} using namespace Maxflow;
void shai() {
for(int i=2;i<=maxn;++i) {
if(!vis[i])
prime[++prcnt] = i;
for(int j=1;i*prime[j] <= maxn;++j) {
vis[i*prime[j]] = 1;
if(i % prime[j] == 0)
break;
}
}
vis[2] = 1;
vis[1] = 1;
}
void solve() {
int jcnt = 0, ocnt = 0;
SS = 1001, TT = 1002;
// 奇数左边 偶数右边
for(int i=1;i<=n;++i) {
if(x[i] % 2 == 1)
jcnt++, ade(SS, i, 1);
else
ocnt++, ade(i, TT, 1);
for(int j=i+1;j<=n;++j) {
if(!vis[x[j] - x[i]]) {
if(x[j] % 2 == 1)
ade(j, i, 1);
else
ade(i, j, 1);
}
}
}
int bas = dinic(SS, TT);
jcnt -= bas, ocnt -= bas;
int ans = bas;
ans += (jcnt / 2) * 2, jcnt = jcnt % 2;
ans += (ocnt / 2) * 2, ocnt = ocnt % 2;
if(jcnt + ocnt != 0)
ans += 3;
cout<<ans;
return;
}
int main() {
shai();
scanf("%d", &m);
for(int i=1;i<=m;++i)
scanf("%d", &y[i]);
x[++n] = y[1];
for(int i=2;i<=m;++i) {
if(y[i] != y[i-1] + 1) {
x[++n] = y[i-1] + 1;
x[++n] = y[i];
}
}
x[++n] = y[m] + 1;
// for(int i=1;i<=n;++i)
// printf("%d ",x[i]);
// printf("\n");
solve();
return 0;
}