【前言】
这场比赛属实阴间,题十分诡异。
最后rk78,校3/9

1001. Yes Prime Minister

【题目】

给定一个数 x x x,求一个最短的区间 [ l , r ] [l,r] [l,r]使得 x ∈ [ l , r ] x\in[l,r] x∈[l,r]且 ∑ i = l r i \sum_{i=l}^ri ∑i=lr​i是一个素数。

T ≤ 1 0 6 , ∣ x ∣ ≤ 1 0 7 T\leq 10^6,|x|\leq 10^7 T≤106,∣x∣≤107

【思路】

一个结论是,最后这个 ∑ \sum ∑至多由两个数组成(确切地说,一堆相反数加上两个连续的数)。

证明十分简单,首先一个数加上它的相反数可以变为0,这样我们就可以找到一个包含 x x x的区间,然后我们考虑正数,连续三个数一定是 3 3 3的倍数,连续四个数一定是 2 2 2的倍数,连续五个数一定是 5 5 5的倍数,于是后面也显然都不是素数了。

因此我们只需要考虑 x x x和 x − 1 , x + 1 x-1,x+1 x−1,x+1能否组成素数,不行的话就一路往上扩增即可。

复杂度 O ( T + N ) O(T+N) O(T+N)

【参考代码】

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a),i##ss=(b);i<=i##ss;i++)
#define dwn(i,a,b) for(int i=(a),i##ss=(b);i>=i##ss;i--)
#define deb(x) cerr<<(#x)<<":"<<(x)<<'\n'
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
#define hvie '\n'
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
int yh(){int ret=0;bool f=0;char c=getchar();while(!isdigit(c)){if(c==EOF)return -1;if(c=='-')f=1;c=getchar();}while(isdigit(c))ret=(ret<<3)+(ret<<1)+(c^48),c=getchar();return f?-ret:ret;
}
const int maxn=4e5+5;
int prm[maxn*100];bool vis[maxn*100];
int tot=0;
void euler(int n){for(int i=2;i<=n;i++){if(!vis[i]) prm[++tot]=i;for(int j=1;j<=tot&&prm[j]*i<=n;j++){vis[i*prm[j]]=1;if(i%prm[j]==0) break;}}
}
bool isprim(ll x){if(x<=1) return 0;return !vis[x];
}
bool isp(ll x){if(x<=1) return 0;for(ll i=2;i*i<=x;i++){if(x%i==0) return 0;}return 1;
}
int bf(int x,int &l,int &r){for(int d=1;;d++){for(int st=x-d+1;st<=x;st++){ll ed=st+d-1;ll sum=(ed+st)*(ed-st+1)/2ll;if(isp(sum)){l=st,r=ed;// cout<<st<<" "<<ed<<" ";return d;}}}
}
int calc(int x){// cerr<<x<<hvie;if(isprim(x)) return 1;if(isprim(x+x+1)) return 2;if(isprim(x+x-1)) return 2;int ans=x+x+1;for(x++;;x++,ans+=2){if(isprim(x)) return ans+1;if(isprim(x+x+1)) return ans+2;}
}int main(){// freopen("my.out","r",stdin);// freopen("myout","w",stdout);euler(3e7+1000);dwn(_,yh(),1){int x=yh();if(x<0){int ans=-x-x+1;x=-x+1;for(;;x++,ans+=2){if(isprim(x)) {ans++;break;}if(isprim(x+x+1)) {ans+=2;break;}}cout<<ans<<hvie;}else{cout<<calc(x)<<hvie;}}return 0;
}

1002. Might and Magic

一个人的属性用 A i , D i , P i , K i , H i A_i,D_i,P_i,K_i,H_i Ai​,Di​,Pi​,Ki​,Hi​表示, i = 1 i=1 i=1表示敌人, i = 0 i=0 i=0表示自己。

i i i对 1 − i 1-i 1−i攻击,物理攻击造成 C p max ⁡ ( 1 , A i − D 1 − i ) C_p\max(1,A_i-D_{1-i}) Cp​max(1,Ai​−D1−i​)的伤害,魔法攻击造成 C m P i C_mP_i Cm​Pi​的伤害,但是魔法攻击只能使用 K i K_i Ki​次。 H i H_i Hi​是血量。 P 1 = K 1 = 0 P_1=K_1=0 P1​=K1​=0,即敌人只会物理攻击。

现在有 T T T组数据,每组数据给出 C p , C m , H 0 , A 1 , D 1 , N C_p,C_m,H_0,A_1,D_1,N Cp​,Cm​,H0​,A1​,D1​,N, N N N为你能分配给 A 0 , D 0 , P 0 , K 0 A_0,D_0,P_0,K_0 A0​,D0​,P0​,K0​的点数,问 H 1 H_1 H1​最多是多少时你仍然能获胜(你先手)。

问题即最多能打敌人多少血。

首先我们发现我们活的轮次由防御力决定也就是我们能出手 k k k次,有 ( k − 1 ) ⋅ d < H 0 (k-1)\cdot d<H_0 (k−1)⋅d<H0​,其中 d = C p ( A 1 − D 0 ) d=C_p(A_1-D_0) d=Cp​(A1​−D0​),为了方便我们显然可以把 H 0 − 1 H_0-1 H0​−1先除以 C p C_p Cp​。则 k = ⌈ H 0 − 1 d ⌉ + 1 ⇒ d = ⌊ H 0 − 1 k ⌋ + 1 k=\lceil\frac {H_0-1} {d}\rceil +1\Rightarrow d=\lfloor\frac {H_0-1} {k }\rfloor+1 k=⌈dH0​−1​⌉+1⇒d=⌊kH0​−1​⌋+1,当然边界条件是 d = A i − D 1 − i = 1 d=A_i-D_{1-i}=1 d=Ai​−D1−i​=1,即最多出手 k = H 0 k=H_0 k=H0​次。

这个 k k k最多 O ( H ) O(\sqrt{H}) O(H ​)个取值,因此我们可以直接枚举。

接下来我们考虑分配攻击,一个猜想是我们肯定只全点物理或者全点魔法。

设分配物理攻击 x x x次,物理伤害函数 F ( x ) = x ⋅ C p max ⁡ ( 1 , x − D 1 ) F(x)=x\cdot C_p\max(1,x-D_1) F(x)=x⋅Cp​max(1,x−D1​),是一个下凸函数。

设分配魔法攻击 x x x次,魔法伤害函数 G ( x ) = min ⁡ ( k , x ) ⋅ C m ⋅ ( P 0 − x ) G(x)=\min(k,x)\cdot C_m\cdot (P_0-x) G(x)=min(k,x)⋅Cm​⋅(P0​−x),也是一个下凸函数

总伤害函数是 P ( x ) = F ( x ) + G ( N − D 0 − x ) P(x)=F(x)+G(N-D_0-x) P(x)=F(x)+G(N−D0​−x),关于物理加点 x x x也是一个下凸函数,于是最大值必然在一个端点处取到。

全加物理的情况就是全加 A 0 A_0 A0​,全加魔法就是对 C m K 0 ( N − D 0 − K 0 ) + C p ( k − K 0 ) ( 0 ≤ K 0 ≤ min ⁡ ( k , N − D 0 ) ) C_mK_0(N-D_0-K_0)+C_p(k-K_0)(0\leq K_0\leq \min(k,N-D_0)) Cm​K0​(N−D0​−K0​)+Cp​(k−K0​)(0≤K0​≤min(k,N−D0​))求最值。

复杂度 O ( T H ) O(T\sqrt H) O(TH ​)

#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
#define int long long
using namespace std;typedef double db;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<int,ll> pil;ll H0,A1,D1,n;
ll Cm,Cp;ll magic(ll k,ll left,ll x)
{if(x<0 || x>min(left,k)) return 0;return Cm*(left-x)*x+Cp*(k-x);
}ll calc(ll k,ll left)//D1
{ll ret=0;ret=max(ret,max(1ll,left-D1)*Cp*k);ret=max(ret,magic(k,left,0));ret=max(ret,magic(k,left,min(k,left)));ret=max(ret,magic(k,left,(Cm*left-Cp)/(2*Cm)));ret=max(ret,magic(k,left,(Cm*left-Cp-1)/(2*Cm)+1));return ret;
}signed main()
{ //freopen("1002.in","r",stdin);//freopen("my.out","w",stdout);int T;scanf("%lld",&T);while(T--){scanf("%lld%lld%lld%lld%lld%lld",&Cp,&Cm,&H0,&A1,&D1,&n);ll ans=calc(1,n);for(int l=1,r,up=(H0-1)/Cp,k;l<=up;l=r+1){r=up/(up/l);k=up/l+1;// printf("nowk:%lld %lld\n",k,r);int D0=A1-r;if(n<D0) continue;if(D0<0) D0=0;//printf("%lld %lld %lld\n",k,n-D0,calc(k,n-D0));ans=max(ans,calc(k,n-D0));//if(!D0) break;}printf("%lld\n",ans);}return 0;
}

1003. 0 Tree

【题意】

一颗 n n n个点的树,有点权和边权。

现在可以进行不超过 4 n 4n 4n次操作,每次可以选择一条路径 u , v u,v u,v,使得 u u u和 v v v的点权 a u , a v a_u,a_v au​,av​异或上 w w w,同时 u , v u,v u,v上的每条边分别加上 ( − 1 ) k ⋅ w (-1)^k\cdot w (−1)k⋅w,其中 k k k是这是路径上第几条边。

要求最终所有点权和边权都变为 0 0 0,

n ≤ 1 0 4 , w i ≤ 1 0 9 n\leq 10^4,w_i\leq 10^9 n≤104,wi​≤109

【思路】

首先我们考虑点权,要让点权变为0,我们只需要从叶子开始一路异或上去就行了。

接下来我们考虑仅对一条边操作,那么连续异或一个数 w w w两次,相当于点权没有变化,而这条边加上了 w w w,而可以观察到这个边权的和,只能变大不能变小,所以我们肯定希望我们在对点操作的同时对边权影响小。

于是我们以一个叶子为根,对这棵树黑白染色,相邻两个同色点一路异或到根,这样可以使得边权和不变。操作完以后,就是根和它相连的一个点权值异或某个数,这样全部点权都为0。

接下来考虑边权,我们同样是从叶子开始,每相邻两条往根的边,把靠近叶子的边权变为0,如果可以满足要求,最后一定剩下根节点的那条边是非正权,其余边权为0,就做完了。

复杂度 O ( n ) O(n) O(n)

【参考代码】

#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
#define ri register int
using namespace std;typedef double db;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<int,ll> pil;
const int N=1e4+10;int n,tot,rt;
int head[N],du[N];
ll a[N];struct Tway
{int v,nex;ll w;Tway(int _v=0,ll _w=0,int _nex=0){v=_v;w=_w;nex=_nex;}
};
Tway e[N<<1];
void add(int x,int y,ll w)
{e[++tot]=Tway(y,w,head[x]);head[x]=tot;e[++tot]=Tway(x,w,head[y]);head[y]=tot;
}struct node
{int x,y;ll w;node(int _x=0,int _y=0,ll _w=0){x=_x;y=_y;w=_w;}
};
vector<node>ans;void init()
{ans.clear();for(int i=1;i<=n;++i) head[i]=du[i]=a[i]=0;rt=tot=1;scanf("%d",&n);//printf("%d\n",n);for(int i=1;i<=n;++i) scanf("%lld",&a[i]);for(int i=1;i<n;++i) {int x,y;ll w;scanf("%d%d%lld",&x,&y,&w);//printf("%d %d %lld\n",x,y,w);add(x,y,w);++du[x];++du[y];}for(int i=1;i<=n;++i) {if(du[i]==1){rt=i;break;}}
}void dfs1(int x,int f1,int f2)
{for(int i=head[x];i;i=e[i].nex){int v=e[i].v;if(v!=e[f1].v) dfs1(v,i^1,f1);}if(f2){ll w=a[x];a[e[f2].v]^=a[x];a[x]=0;e[f1].w+=w;e[f1^1].w+=w;e[f2].w-=w,e[f2^1].w-=w;ans.pb(node(x,e[f2].v,w));}
}void dfs2(int x,int f1,int f2)
{for(int i=head[x];i;i=e[i].nex){int v=e[i].v;if(v!=e[f1].v) dfs2(v,i^1,f1);}if(f2){ll w=e[f1].w/2;ans.pb(node(x,e[f2].v,-w));ans.pb(node(x,e[f2].v,-w));e[f1].w=e[f1^1].w=0;e[f2].w+=w*2;e[f2^1].w+=w*2;}
}bool solve()
{dfs1(rt,0,0);if(a[rt]^a[e[head[rt]].v]){return 0;}if(n!=1) {ans.pb(node(rt,e[head[rt]].v,a[rt]));}e[head[rt]].w+=a[rt];e[head[rt]^1].w+=a[rt];ll sum=0;for(int i=2;i<=tot;i+=2) {sum+=e[i].w;if((e[i].w%2+2)&1) return 0;}if(sum>0) return 0;dfs2(rt,0,0);if(n!=1) {ans.pb(node(rt,e[head[rt]].v,-e[head[rt]].w/2));ans.pb(node(rt,e[head[rt]].v,-e[head[rt]].w/2));}return 1;
}int main()
{ //freopen("1003.in","r",stdin);//freopen("my.out","w",stdout);int T;scanf("%d",&T);//printf("%d\n",T);while(T--){init();if(!solve()) puts("NO");else{puts("YES");printf("%d\n",(int)ans.size());for(auto t:ans){if(t.w<0) swap(t.x,t.y),t.w=-t.w;assert(t.w<=(ll)1e14);printf("%d %d %lld\n",t.x,t.y,t.w);}}}return 0;
}

Decomposition

【题意】

一个 n n n个点的完全图,要求找到 k k k条简单路径,长度分别为 a i a_i ai​.

n ≤ 1000 , n ≡ ( 1 mod  2 ) , k ≤ n ( n − 1 ) 2 , ∑ a i = n ( n − 1 ) 2 , a i ≤ n − 3 n\leq 1000,n\equiv(1\text{mod } 2), k\leq \frac {n(n-1)} 2,\sum a_i=\frac {n(n-1)} 2,a_i\leq n-3 n≤1000,n≡(1mod 2),k≤2n(n−1)​,∑ai​=2n(n−1)​,ai​≤n−3

【思路】

事实上题目是要求一个欧拉回路,使得任意连续 n − 2 n-2 n−2个点两两不一样。

比赛的时候当然是。。。打表找规律。

考虑形如下面左图构造的一个简单环。构造方法是从中心点出发,将剩余点分为左上、右下两部分,交错地将当前点与两部分的点连边,最后回到中心点。可以证明这种构造通过不断旋转 2 π ⋅ 2 n − 1 2\pi ·\frac 2 {n-1} 2π⋅n−12​弧度可以得到 n − 1 2 \frac {n-1} 2 2n−1​个不同的环,且这些环恰好经过完全图所有边各一次。将这些环按照旋转顺序拼接起来即可得到完全图的一条欧拉回路,可以证明这条欧拉回路任意连续n − 2 个点都两两不重复。故直接将这条欧拉回路按照题意要求顺序切分为若干路径即可。

【参考代码】

#include <bits/stdc++.h>using namespace std;void solve() {int n, t, ptr = 0; scanf("%d%d", &n, &t);vector<int> euler(1, n-1);for(int i = 0; i < n/2; ++i) {int sgn = 1, ct = i;for(int d = 1; d < n; ++d) {euler.push_back(ct);ct = (ct + sgn*d + n-1) % (n-1);sgn *= -1;}euler.push_back(n-1);}while(t--) {int len; scanf("%d", &len);len++;while(len--) {printf("%d%c", euler[ptr++]+1, " \n"[len == 0]);}ptr--;}
}
int main(){int T; scanf("%d", &T);for(int i = 1; i <= T; ++i) {printf("Case #%d:\n", i);solve();}return 0;
}

1005. Median

【题目】

1 ∼ n 1\sim n 1∼n这些数字分成 k k k组,使得第 i i i组的中位数是 b i b_i bi​(假如有 t t t个数,中位数是第 ⌊ t + 1 2 ⌋ \lfloor \frac {t+1} 2 \rfloor ⌊2t+1​⌋小的)

n ≤ 1 0 5 n\leq 10^5 n≤105

【思路】

这个东西做法应该很多,比较明显的是反悔贪心,或者考虑按顺序维护每个数字在前后最多和最少能匹配多少个数。具体实现可以参考代码。。。

复杂度应该都是 O ( n log ⁡ n ) O(n\log n) O(nlogn)

【参考代码】

反悔贪心

/** @date:2021-08-05 12:13:12* @source:*/
#include <bits/stdc++.h>using namespace std;typedef pair<int, int> pii;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
#define fir first
#define sec second
#define ALL(x) (x).begin(), (x).end()
#define SZ(x) (int)x.size()
#define up(i, l, r) for (int i = l; i <= r; ++i)
#define dn(i, l, r) for (int i = l; i >= r; --i)
#define Trav(i, x) for (auto &i : x)
#define pb push_back
template <class T, class G> bool chkMax(T &x, G y) {return y > x ? x = y, 1 : 0;
}
template <class T, class G> bool chkMin(T &x, G y) {return y < x ? x = y, 1 : 0;
}int N, M;
set<int> s;
vi v, l;bool solve() {cin >> N >> M;v.resize(M);s.clear();l.clear();up(i, 1, N) s.insert(i);Trav(x, v) {cin >> x;s.erase(x);}sort(ALL(v));int p = SZ(v) - 1;while (!s.empty()) {int x = *--s.end();s.erase(x);while (p >= 0 && v[p] > x)--p;if (p < 0) {s.insert(x);break;}if (s.empty())return true;auto a = s.lower_bound(v[p]);if (a == s.begin()) {--p;continue;}--a;l.push_back(*a);s.erase(*a);}if (s.empty())return true;p = 0;while (p < SZ(v) && v[p] < *--s.end())p++;if (p == SZ(v))return false;int cnt = 0;Trav(x, l) {if (x > v[p])++cnt;}return cnt * 2 >= SZ(s);
}string ans[2] = {"NO", "YES"};int main() {ios_base::sync_with_stdio(false);cin.tie(NULL);int Case;cin >> Case;while (Case--)cout << ans[solve()] << "\n";return 0;
}

xjb维护

#include <bits/stdc++.h>using namespace std;int main() {ios::sync_with_stdio(false);cin.tie(0);int T;cin >> T;while (T--) {int n, m;cin >> n >> m;assert(m >= 1 && m <= n && n <= 100000);vector<int> f(n + 2);f[n + 1] = 1;while (m--) {int v;cin >> v;assert(v >= 1 && v <= n);assert(f[v] == 0);f[v] = 1;}vector<pair<int, int>> size;int have = 0;int count = 0;for (int i = 1; i <= n + 1; i++) {if (f[i]) {if (have) {size.push_back(make_pair(have, count));}have = 0;count += 1;} else {have += 1;}}sort(size.begin(), size.end());if (size.empty()) {cout << "YES\n";continue;}int sum = 0;for (auto s: size) {sum += s.first;}if (size.back().first <= sum - size.back().first + size.back().second) {cout << "YES\n";} else {cout << "NO\n";}}return 0;
}

1006. The Struggle

略,不会。

1007. Power Station of Art

【题目】

有两幅 n n n个点的同构图,但是点的颜色和点权不一样(只有两种颜色)。

现在每次可以操作一条边,交换两点的点权,若两点颜色一样,则还会翻转它们的颜色。

问两幅图能不能完全一样。

n ≤ 1 0 6 n\leq 10^6 n≤106

【思路】

首先这个点权和颜色独立就很难办,但是我们可以修改一下它的操作:每次交换两个点的颜色和点权,然后将颜色翻转,这样显然是等价的。

现在,如果一个数字被交换奇数次,它的颜色就会翻转,否则不会。然后我们分类讨论:

  • 图是一个二分图。那么我们把这个图黑白染色,我们发现对于一个数字,如果我们知道这个数字初始的黑白染色的颜色和节点的颜色,我们把这个数字交换到任何一个位置后,对应的节点的颜色就是已知的了。而且,由于图是联通的,数字是可以任意排列到所有节点上的。那么这时条件就是将数字按照(节点颜色异或数字颜色)分成两个可重集合,题目中两个图的这两个可重集合必须是一样的。

  • 图不是一个二分图。这时候联通块里会有一个奇环。此时的条件是输入两个图里所有数字的可重集合必须相同,且颜色个数的奇偶性不能改变。这是由于我们可以把图看成一个二分图加上一些多余的边,我们可以对于任何一个奇环构造一个方案使得所有的数字不动,且只有两个位置的颜色翻转,不论那两个位置开始颜色如何。方案就是:对于奇环上的点顺序编号为1 到n,先进行n-1 次操作将1 上的数字交换到n 号节点,再进行一次操作交换1 号和n号节点上的数字,再用n-2 次操作将n 号节点上的数字交换到二号节点。

复杂度 O ( n + m ) O(n+m) O(n+m)

【参考代码】

//    苔花如米小,也学牡丹开。
//    Zhikun Wang (nocriz)
//    $_DATE#include <bits/stdc++.h>
using namespace std;using ll = long long; using db = long double; using str = string;
using pi = pair<int,int>; using pl = pair<ll,ll>; using pd = pair<db,db>;
using vi = vector<int>; using vb = vector<bool>; using vl = vector<ll>;
using vd = vector<db>; using vs = vector<str>;
using vpi = vector<pi>; using vpl = vector<pl>; using vpd = vector<pd>;#define tcT template<class T
#define tcTU tcT, class U
tcT> using V = vector<T>;  tcT, size_t SZ> using AR = array<T,SZ>; tcT> using PR = pair<T,T>;#define mp make_pair
#define f first
#define s second
#define sz(x) int((x).size())
#define bg(x) begin(x)
#define all(x) bg(x), end(x)
#define rall(x) x.rbegin(), x.rend()
#define sor(x) sort(all(x))
#define rsz resize
#define ins insert
#define ft front()
#define bk back()
#define pb push_back
#define eb emplace_back
#define pf push_front
#define lb lower_bound
#define ub upper_boundtcT> int lwb(V<T>& a, const T& b) { return int(lb(all(a),b)-bg(a)); }#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define ROF(i,a,b) for (int i = (b)-1; i >= (a); --i)
#define R0F(i,a) ROF(i,0,a)
#define each(a,x) for (auto& a: x)const int MOD = 998244353;
const ll INF = 1e18; // not too close to LLONG_MAX
const db PI = acos((db)-1);
const int dx[4] = {1,0,-1,0}, dy[4] = {0,1,0,-1}; // for every grid problem!!
mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());
template<class T> using pqg = priority_queue<T,vector<T>,greater<T>>;constexpr int pct(int x) { return __builtin_popcount(x); } // # of bits set
constexpr int bits(int x) { return x == 0 ? 0 : 31-__builtin_clz(x); } // floor(log2(x))
constexpr int p2(int x) { return 1<<x; }
constexpr int msk2(int x) { return p2(x)-1; }
ll cdiv(ll a, ll b) { return a/b+((a^b)>0&&a%b); } // divide a by b rounded up
ll fdiv(ll a, ll b) { return a/b-((a^b)<0&&a%b); } // divide a by b rounded down
tcT> bool ckmin(T& a, const T& b) { return b < a ? a = b, 1 : 0; }
tcT> bool ckmax(T& a, const T& b) { return a < b ? a = b, 1 : 0; }
tcTU> T fstTrue(T lo, T hi, U f) { hi ++; assert(lo <= hi); while (lo < hi) { T mid = lo+(hi-lo)/2; f(mid) ? hi = mid : lo = mid+1; } return lo; }
tcTU> T lstTrue(T lo, T hi, U f) { lo --; assert(lo <= hi); while (lo < hi) { T mid = lo+(hi-lo+1)/2; f(mid) ? lo = mid : hi = mid-1; } return lo; }
tcT> void remDup(vector<T>& v) { sort(all(v)); v.erase(unique(all(v)),end(v)); }
tcTU> void erase(T& t, const U& u) { auto it = t.find(u); assert(it != end(t)); t.erase(it); } int ans = 1;
vi vis;
vi G[1000030];
int color[2][1000030],val[2][1000030];int can = 0,cs[2];
vi cC[2],cS[2][2];void dfs(int num,int ccol = 2){if(vis[num]){if(vis[num]!=ccol)can = 0;return;}vis[num] = ccol;F0R(i,2){cC[i].pb(val[i][num]);cs[i]^=color[i][num];cS[i][(ccol-2)^color[i][num]].pb(val[i][num]);}each(ct,G[num])dfs(ct,ccol^1);
}
void solve(){ans = 1;int n,m;cin>>n>>m;vis.clear();vis.rsz(n+10,0);F0R(i,n+5)G[i].clear();F0R(i,m){int u,v;cin>>u>>v;G[u].pb(v);G[v].pb(u);}F0R(j,2){FOR(i,1,n+1)cin>>val[j][i];FOR(i,1,n+1){char ch;cin>>ch;color[j][i] = (ch == 'R');}}FOR(i,1,n+1){if(!vis[i]){F0R(j,2){cs[j] = 0;cC[j].clear();cS[0][j].clear();cS[1][j].clear();}can = 1;dfs(i);sor(cC[0]);sor(cC[1]);sor(cS[0][0]);sor(cS[1][0]);sor(cS[0][1]);sor(cS[1][1]);if(cC[0]!=cC[1])ans = 0;if(can && (cS[0][0]!=cS[1][0] || cS[0][1]!=cS[1][1]))ans = 0;if(!can && cs[0]!=cs[1])ans = 0;}}if(ans){puts("YES");}else{puts("NO");}
}int main() {ios::sync_with_stdio(false);int t;cin>>t;while(t--){solve();}// END OF CODEreturn 0;
}

1008. Command and Conquer: Red Alert 2

【题目】

三维空间中有 n n n个敌人分别在 ( x i , y i , z i ) (x_i,y_i,z_i) (xi​,yi​,zi​),你在一个位置能够打到的人是曼哈顿距离不超过 k k k的敌人,你从 ( − inf ⁡ , − inf ⁡ , − inf ⁡ ) (-\inf,-\inf,-\inf) (−inf,−inf,−inf)出发,只能往上或往右走,问 k k k最少是多少能消灭所有敌人。

n ≤ 5 × 1 0 5 n\leq 5\times 10^5 n≤5×105

【思路】

考虑范围为 k k k时,攻击到的所有位置是一个边长为 2 k 2k 2k的立方体,那么问题显然可以转化为:把自己放到立方体的最下角,每次移动到所有剩下人的 ( m i n x , m i n y , m i n z ) (min_x,min_y,min_z) (minx​,miny​,minz​)的位置,然后把 k k k增大(或不变)至能继续移动(也即把某一维最小的敌人全部消灭),这个过程是可以贪心的。

复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

【参考代码】

#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
using namespace std;typedef double db;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<int,ll> pil;const int N=5e5+10,inf=2e9;
int n;
bool fg[N];struct node
{int x[3],id;node(int a=0,int b=0,int c=0,int _id=0){x[0]=a;x[1]=b;x[2]=c;id=_id;}
};
node a[N],b[N],c[N];int op;
bool cmp(const node&a,const node&b)
{return a.x[op]<b.x[op];
}
void gmax(int &x,int y){x=max(x,y);}int getk(node a,int x,int y,int z)
{return (max(abs(a.x[0]-x),max(abs(a.x[1]-y),abs(a.x[2]-z)))+1)/2;
}void init()
{for(int i=0;i<=n;++i) fg[i]=0;
}int main()
{ //freopen("1008.in","r",stdin);//freopen("my.out","w",stdout);int T;scanf("%d",&T);while(T--){init();scanf("%d",&n);for(int i=1;i<=n;++i) {scanf("%d%d%d",&a[i].x[0],&a[i].x[1],&a[i].x[2]),a[i].id=i;b[i]=a[i];c[i]=a[i];}op=0;sort(a+1,a+n+1,cmp);op=1;sort(b+1,b+n+1,cmp);op=2;sort(c+1,c+n+1,cmp);int x=-inf,y=-inf,z=-inf,ix=1,iy=1,iz=1,k=0;for(;ix<=n;){while(ix<=n && fg[a[ix].id]) ++ix;while(iy<=n && fg[b[iy].id]) ++iy;while(iz<=n && fg[c[iz].id]) ++iz;if(ix>n || iy>n || iz>n) break;x=a[ix].x[0];y=b[iy].x[1];z=c[iz].x[2];int tkx=getk(a[ix],x,y,z),tky=getk(b[iy],x,y,z),tkz=getk(c[iz],x,y,z);gmax(k,min(tkx,min(tky,tkz)));if(tkx<=k) fg[a[ix++].id]=1;if(tky<=k) fg[b[iy++].id]=1;if(tkz<=k) fg[c[iz++].id]=1;}printf("%d\n",k);}return 0;
}

1009. Typing Contest

略,虽然想到了前半部分,但是后面不太会,数学功底不太行,就咕咕咕了,感觉不太能推广。

1010. Array

略,看题就觉得和什么方格图上的阶梯有关,不过懒得推了。

1011. Game

【题目】

博弈,每次对于一个 [ l , r ] [l,r] [l,r],可以把区间变为 [ l + 1 , r ] [l+1,r] [l+1,r]或 [ l , r − 1 ] [l,r-1] [l,r−1],变成 [ x , x ] [x,x] [x,x]的人赢。但是现在有另外 n n n个限制,表示变成 [ a i , b i ] [a_i,b_i] [ai​,bi​]的人也会赢。

给出 q q q个区间 [ l i , r i ] [l_i,r_i] [li​,ri​],问每个比赛谁会赢。

n , q ≤ 1 0 5 , a i , b i , l i , r i ≤ 1 0 9 n,q\leq 10^5,a_i,b_i,l_i,r_i\leq 10^9 n,q≤105,ai​,bi​,li​,ri​≤109

【思路】

画个方格图,不难看出,没有特殊限制的时候就是一斜行输赢状态一样,现在新的限制会导致这个状态变化。更确切地说:如果一个点 ( i , j ) (i, j) (i,j) 任意走一步或任意走两步所到达的点都不是特殊点,那么经过简单的分类讨论, ( i + 1 , j − 1 ) (i + 1, j − 1) (i+1,j−1) 的胜负状态和 ( i , j ) (i, j) (i,j) 是相同的。

特殊点只有 O ( n ) O(n) O(n)个,所以不能规约到 ( i + 1 , j − 1 ) (i + 1, j − 1) (i+1,j−1)的点也只有 O ( n ) O(n) O(n) 个。把这些点全都提出来,然后跑记忆化搜索即可,普通点就直接按照 ( i + j ) (i + j) (i+j) 往下找到第一个没法规约的点,没法规约的点暴力枚举两种转移,复杂度 O ( ( n + q ) l o g ( n + q ) ) O((n + q) log(n + q)) O((n+q)log(n+q))。

当然了,记忆化搜索常数有点大,于是我们还可以用扫描线做。

【参考代码】

扫描线

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a),i##ss=(b);i<=i##ss;i++)
#define pb push_back
#define fi first
#define se second
#define hvie '\n'
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
int yh(){int ret=0;bool f=0;char c=getchar();while(!isdigit(c)){if(c==EOF)return -1;if(c=='-')f=1;c=getchar();}while(isdigit(c))ret=(ret<<3)+(ret<<1)+(c^48),c=getchar();return f?-ret:ret;
}
const int maxn=3e5+5;
int n,m;
int dt[maxn*8],cc;
int sz[maxn*32],val[maxn*32],tot=0,ls[maxn*32],rs[maxn*32];
int root[maxn*8];
struct pt{int x,y,z;bool operator<(const pt&A)const{return y-x<A.y-A.x;}
}p[maxn*8];
int ans[maxn];
map<pii,bool>spe;
#define mid ((l+r)>>1)
void ins(int &x,int l,int r,int pos,int vl){if(!x) {x=++tot;val[x]=-1;sz[x]=ls[x]=rs[x]=0;}sz[x]++;if(l==r) return val[x]=vl,void();(pos<=mid) ? ins(ls[x],l,mid,pos,vl):ins(rs[x],mid+1,r,pos,vl);
}
int ask(int x,int l,int r,int pos){if(!x) return -1;if(l==r) return val[x];if(pos>mid) return ask(rs[x],mid+1,r,pos);if(sz[ls[x]]){int lans=ask(ls[x],l,mid,pos);return ~lans?lans:ask(rs[x],mid+1,r,pos);}return ask(rs[x],mid+1,r,pos);
}int qry(int x,int y){int z=lower_bound(dt+1,dt+1+cc,x+y)-dt;// cout<<"qry "<<x<<" "<<y<<hvie;if(dt[z]!=x+y) return (y-x)&1;int ret=ask(root[z],1,1e9,x);return ~ret?ret:(y-x)&1;
}int main(){// freopen("my.in","r",stdin);// freopen("1011.in","r",stdin);// freopen("my2.out","w",stdout);dwn(_,yh(),1){spe.clear();tot=0;n=yh(),m=yh();int cp=0;dt[0]=0;rep(i,1,n){int x=yh(),y=yh(),z=yh();p[++cp]=(pt){x,y,z};spe[{x,y}]=z;}rep(i,1,n){int x=p[i].x,y=p[i].y;if(x>1&&!spe.count({x-1,y}))  p[++cp]=(pt){x-1,y,-1};if(!spe.count({x,y+1}))       p[++cp]=(pt){x,y+1,-1};if(x>1&&!spe.count({x-1,y+1}))p[++cp]=(pt){x-1,y+1,-1};if(x>2&&!spe.count({x-2,y}))  p[++cp]=(pt){x-2,y,-1};if(!spe.count({x,y+2}))       p[++cp]=(pt){x,y+2,-1};rep(k,0,2){dt[++dt[0]]=p[i].x+p[i].y-k;}}sort(dt+1,dt+1+dt[0]);cc=unique(dt+1,dt+1+dt[0])-dt-1;sort(p+1,p+1+cp);rep(i,1,cp)if(p[i].z==-1){if(p[i].x>1e9||p[i].y>1e9) break;// if(p[i].x>n||p[i].y>n) break;int x=p[i].x,y=p[i].y,z=lower_bound(dt+1,dt+1+cc,x+y)-dt;bool r,d,now;if(spe.count({x+1,y})) r=spe[{x+1,y}];else r=qry(x+1,y);if(spe.count({x,y-1})) d=spe[{x,y-1}];else d=qry(x,y-1);now=(!r||!d);// cout<<x<<" "<<y<<" : "<<r<<" "<<d<<" "<<now<<hvie;ins(root[z],1,1e9,x,now);}rep(__,1,m){int x=yh(),y=yh();bool r,d;if(spe.count({x,y})) {// cout<<"*";continue;cout<<spe[{x,y}];continue;}cout<<qry(x,y);}cout<<hvie;rep(i,1,dt[0]){root[i]=0;}}return 0;
}

std记忆化

#include<bits/stdc++.h>
using namespace std;
map<int,int>pos;
vector<map<int,int> >f;
int T,n,q;
const int inf=2e9;
void init()
{pos.clear();vector<map<int,int> >().swap(f);
}
int ins(int x,int y,int z)
{map<int,int>::iterator it;it=pos.find(x+y);if(it==pos.end()){f.push_back(map<int,int>());pos[x+y]=f.size()-1;    }int idx=pos[x+y];it=f[idx].find(x);int ok=0;if(it==f[idx].end())f[idx][x]=z,ok=1;else if(it->second==-1)it->second=z;else return it->second;if(ok)return -1;else return -2;
}
int ask(int x,int y)
{int res=ins(x,y,-1);if(res>=0)return res;if(y-x+1<=2)res=-2;map<int,int>::iterator it;int ans;if(res==-1){  int bk=(x+y)/2,pre=inf;  int idx=pos[x+y];it=f[idx].upper_bound(x);if(it!=f[idx].end())pre=it->first;bk=min(bk,pre);ans=ask(bk,y-(bk-x));}else{if(x==y)ans=0;else ans=!(ask(x+1,y)&ask(x,y-1));}ins(x,y,ans);return ans;
}
int main()
{scanf("%d",&T);while(T--){int cnt0=0,cnt1=0;scanf("%d%d",&n,&q);init();for(int i=1;i<=n;i++){int x,y,z;scanf("%d%d%d",&x,&y,&z);ins(x,y,z);for(int j=0;j<3;j++)for(int k=0;k<3;k++){if(j==k&&j!=1)continue;if(x-j<1)continue;ins(x-j,y+k,-1);}}for(int i=1;i<=q;i++){int x,y,tmp;scanf("%d%d",&x,&y);//tmp=ask(x,y);if(tmp==0)cnt0++;else cnt1++;printf("%d",ask(x,y));}printf("\n");//  int sum=0;//for(int i=0;i<f.size();i++)sum+=f[i].size();//printf("%d %d %d\n",cnt0,cnt1,sum);}   return 0;
}

【多校训练】2021HDU多校6相关推荐

  1. HDU6578 2019HDU多校训练赛第一场 1001 (dp)

    HDU6578 2019HDU多校训练赛第一场 1001 (dp) 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6578 题意: 你有n个空需要去填,有 ...

  2. 2019牛客多校训练第十场F Popping Balloons

    2019牛客多校训练第十场F Popping Balloons 题意:二维平面内给你若干个点,然后你可以在x轴和y轴分别射三枪(每一枪的间隔是R),问最多能射掉多少气球. 题解:贪心.这个应该只能算作 ...

  3. 【2019杭电多校训练赛】HDU6681 / 1002-Rikka with Cake 题解(扫描线)

    [2019杭电多校训练赛]HDU6681 / 1002-Rikka with Cake 题解 题意 思路 代码 题目来自于:HDU6681 Rikka with Cake 题意 题目的大意是给定你一个 ...

  4. 选完校花又选校草,张朝阳为什么对造星如此执念?

    最近,有一场来自搜狐狐友的热门选秀吸引来了宁静.李斯羽.江映蓉.黄英等女明星评审,搜狐董事局主席兼首席执行官张朝阳也亲临坐镇,评审名单里还有柳岩.于莎莎.瞿颖.赵子琪等知名艺人-- 参赛者不是所谓的明 ...

  5. GPS北斗校时(NTP校时服务器)在某市国土资源局投入使用

    GPS北斗校时(NTP校时服务器)在某市国土资源局投入使用 GPS北斗校时(NTP校时服务器)在某市国土资源局投入使用 许多电脑网络都使用基于互联网的时间服务器以便保持自己系统的同步性.问题是,无论他 ...

  6. 小学教师计算机校本培训计划,校本培训工作计划

    南雁镇中心小学校本培训工作计划 为了进一步提高教师实施素质教育的能力与水平,全力打造一支师德修养高.业务素质精良.教学技能全面.教学基本功过硬.具有一定教科研能力.适应新时期新课程改革需求的教师队伍, ...

  7. 计算机培训校本研修心得,校本研修经验总结

    校本研修经验总结 课堂是教育教学研究的基地,标志着教学研究的重心要置于具体的课堂教学情境中.我们学校全体教师继续更新教育思想和教育观念,改革教学方法,各教研组面向学生均有序地组织了一系列教育教研活动: ...

  8. NTP校时器(NTP网络校时器-NTP校时系统)

    NTP校时器(NTP网络校时器-NTP校时系统) NTP校时器(NTP网络校时器-NTP校时系统) 技术交流-岳峰-15901092122:qq-522508213: 近几年来,随着变电站自动化水平的 ...

  9. 【多校训练】2021HDU多校4

    [前言] 今天写题手感很好,写的都是1A,然而太蠢了做不动- - 开场自己切了三个水题,队友写了一个水题就开始搞不动了,后面就过了一个05. 字符串如此SB的东西都忘了,今天赶紧补回来了. rk53, ...

最新文章

  1. MySQL 和 Innobackup 不定期卡住的秘密
  2. 网络营销外包专员浅析响应式网站建设应注意哪些网络营销外包细节
  3. 【直播提醒】荷小鱼:K12 在线教育应用的开发实践
  4. 一天一道算法题--5.30---递归
  5. c++循环执行一个函数_20川大计算机 | 时间复杂度,你避不开的一个考点
  6. exec go 重启_无停机优雅重启 Go 程序
  7. jQuery初识 - jQuery中的方法
  8. 2748: [HAOI2012]音量调节
  9. AcWing 1813. 方块游戏(暴力枚举)
  10. unity串口 连接多个串口崩溃_必学DB9串口+3种连接方式
  11. Linux V4L2驱动框架分析之(一):架构介绍
  12. xcode 配置wechat_react-native-wechat微信组件的使用
  13. 苹果开发者账户协议更新
  14. 计算天数(函数)(C语言实现)
  15. CISCO 交换设备IOS 备份/恢复操作
  16. CF896C Willem, Chtholly and Seniorious(珂朵莉树)
  17. 机器学习是门手艺,正如编程一样,马上会成为IT人员的必备技能!
  18. 三国大时代java_横跨,塞班、安卓、pc的国产良心作《三国大时代》系列
  19. 2021年,自媒体人该怎么建立自媒体矩阵?
  20. android手机操作手册,数字填图(Android版)操作手册.pdf

热门文章

  1. 如何在PowerPoint中编辑页眉和页脚
  2. alexa 网站的 Site Stats 详解(转)
  3. zabbix常用监控项解读
  4. 【Android Fragment】Fragment基础
  5. git使用报错:Cannot lock
  6. ​卜东波研究员:高观点下的少儿计算思维
  7. 深入理解Java引用(一)
  8. 动态网站的制作与设计_网站设计制作排名
  9. Android仿斗鱼直播的弹幕效果
  10. mediapipe——人体姿势关节点检测(pose模块) 学习笔记(全)