8.13 2020 Multi-University Training Contest 8题解及补题
8.13 2020 Multi-University Training Contest 8题解及补题
比赛过程
题解
A
题意
解法
代码
//将内容替换成代码
B
题意
解法
代码
//将内容替换成代码
C Clockwise or Counterclockwise
题意
给出三个点的坐标,要求判断这三个点组成的圆是顺时针还是逆时针
解法
可以选第一个点和第二点组成一条直线,然后判断第三个点和该直线的关系即可。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const double eps = 1e-8;
const double PI = 3.14159265358979323846264338f;
inline int sgn(const double &x) {
return x < -eps ? -1 : x > eps;
}
struct Point {
double x, y;
Point(double x = 0, double y = 0) : x(x), y(y) {}
void input() {
scanf("%lf%lf", &x, &y);
}
bool operator<(const Point &p) const {
return sgn(x - p.x) < 0 || (!sgn(x - p.x) && sgn(y - p.y) < 0);
}
bool operator==(const Point &p) const {
return !sgn(x - p.x) && !sgn(y - p.y);
}
Point operator+(const Point &p) const {
return Point(x + p.x, y + p.y);
}
Point operator-(const Point &p) const {
return Point(x - p.x, y - p.y);
}
Point operator*(const double c) const {
return Point(x * c, y * c);
}
friend Point operator*(double c, const Point &p) {
return p * c;
}
Point operator/(double c) {
return Point(x / c, y / c);
}
double operator^(const Point &p) const { //揧YН揨b&Vz暲垮害
return x * p.y - y * p.x;
}
double operator%(const Point &p) const { //�圭Н
return x * p.x + y * p.y;
}
double norm() {
return sqrt(x * x + y * y);
}
double arg() { //杩e縨寮у害 锛?pi,pi拞?
return atan2(y, x);
}
friend Point rotate(const Point &v, double A) {
Point p = Point(sin(A), cos(A));
return Point(v ^ p, v % p);
}
friend Point rotate_around_point(const Point &v, const Point &p, double A) {
return rotate(v - p, A) + p;
}
};
struct Line {
Point s, t;
Line(Point s = Point(), Point t = Point()) : s(s), t(t) {}
Point v() {
return t - s;
}
double norm() {
return v().norm();
}
//�逛{�)寸嚎涔[.h�(R隨珑�?online(0),暙U豬暯?1),椤烘i暯?-1)
int relation(Point &p) {
return sgn((v() ^ (p - s)));
}
bool point_on_line(Point &p) { //�规i鴵Z兀nj�)寸嚎涓?宸查sY)
return sgn(v() ^ (p - s)) == 0;
}
bool point_on_seg(Point &p) { //�规i鴵Z兀nj绾挎釋涓?
return point_on_line(p) && sgn((p - s) % (p - t)) <= 0; //揤Tm`如Pc
// return point_on_line(p) && sgn((p - s) % (p - t)) < 0;//涓]匸負Z啶鄉�?
}
double dis_point_line(Point &p) { //�瑰W虜)寸嚎�(R顉涚�?
return fabs((v() ^ (p - s)) / norm());
}
double dis_point_seg(Point &p) { //�瑰W嚏嚎驷寯(R顉涚�?
if (sgn((p - s) % (t - s)) < 0) return (p - s).norm();
if (sgn((p - t) % (s - t)) < 0) return (p - t).norm();
return dis_point_line(p);
}
// 揜ゆg� a, b 撃�`翐fㄧm?绾跨k憮Z\|晶摯h, 琓m`摀枚錸j�)寸嚎涓?
bool same_side(Point &a, Point &b) {
return relation(a) == relation(b);
}
Point pedal(Point &p) { //�瑰犷�)寸嚎�(R雙-瓒?
return s + (p - s) % v() / (v() % v()) * v();
}
Point sym_point(Point &p) { //�?p 揙充|,�)寸嚎�(R脶铉О鏟c
return 2.0 * pedal(p) - p;
}
friend bool isParallel(Line &a, Line &b) { //揜ゆg卿袱鏼?绾挎i鴵Z兀钩琛\媫揤TnZ頃瞉卄庯�?
return !sgn(a.v() ^ b.v());
}
friend bool is_Line_seg_intersection(Line &a, Line &b) { //绾?a)揬\€嚎娈?b)撃�`翑)镐氦锛X[負丰鄉�癸}(宸查sY)
return a.relation(b.s) * a.relation(b.t) <= 0;
}
//揜╃ed�)镐技涓Y鏦褰㈠犷搴e繵〝pTnW氭痚緘彐盤櫢)寸嚎�(R旰?/揙XW綋箩_i鴵Z兀钩琛\媫涓]吂宠€k憮疶mU寭P]唚0浜ょPc(宸查sY)
friend Point line_intersection(Line &a, Line &b) {
double s1 = (a.s - b.s) ^ b.v();
double s2 = (a.t - b.s) ^ b.v();
return (a.t * s1 - a.s * s2) / (s1 - s2);
}
// 瑙R頪謹)镐氦, 涓ょ嚎娈典|帗萗 z翡膏Hoj绔�Pc澶R韐戜氦鏟c
// 揜ゆg晴嚎驷寯)镐氦, 骞舵w0绾挎釋浜ょPc, 1瑙R頪謹)镐氦, 2�)镐氦, 0涓]労�
friend int seg_intersection(Line &a, Line &b, Point &p) {
int d1, d2, d3, d4;
double s1, s2, s3, s4;
d1 = sgn(s1 = a.v() ^ (b.s - a.s));
d2 = sgn(s2 = a.v() ^ (b.t - a.s));
d3 = sgn(s3 = b.v() ^ (a.s - b.s));
d4 = sgn(s4 = b.v() ^ (a.t - b.s));
//瑙R頪謹)镐氦
if (d1 * d2 < 0 && d3 * d4 < 0) {
p = (b.s * s2 - b.t * s1) / (s2 - s1);
return 1;
}
//暼p剁I攟Q猰I浜?
if (a.point_on_seg(b.s) || a.point_on_seg(b.t) || b.point_on_seg(a.s) || b.point_on_seg(b.s)) {
return 2;
}
return 0;
}
//绾挎釋涔[.h�(R靚6�-醓z涚�?
friend double dis_seg_seg(Line &a, Line &b) {
double d1, d2, d3, d4;
Point p;
if (seg_intersection(a, b, p))
return 0;
else {
d1 = a.dis_point_seg(b.s);
d2 = a.dis_point_seg(b.t);
d3 = b.dis_point_seg(a.s);
d4 = b.dis_point_seg(a.t);
return min(min(d1, d2), min(d3, d4));
}
}
};
int main(){
int t;
scanf("%d",&t);
while(t--){
Point a,b,c;
cin>>a.x>>a.y>>b.x>>b.y>>c.x>>c.y;
Line l;
l.s=a;l.t=c;
if(l.relation(b)==1){
cout<<"Clockwise"<<endl;
}
else{
cout<<"Counterclockwise"<<endl;
}
}
}
D Discovery of Cycles
题意
给定n个点m条边的无向图,边的编号为1到m,现在有q次在线询问,每次询问给出l,r(1<=l<=r<=m),
问编号在[l,r]内的边组成的图中是否存在环。
解法
因为3e5个询问,所以可以预处理出以每一个边为起点边形成环需要到达的最早的边
而判环比较简单的是并查集,但是不能每一个起点都重新跑一遍并查集,在起点边编号递增的情况下,
对应的答案编号肯定也是非递减的;所以可以选择删边,且能提供类似并查集判环的数据结构,可以使用LCT
代码
#include<bits/stdc++.h>
#define lc c[x][0]
#define rc c[x][1]
using namespace std;
const int N=3e5+10;
const int M=3e5+10;
int f[N],c[N][2];
int st[N];
bool tag[N];
int R[N];
struct edge{
int from,to;
}e[M];
void init(){
memset(f,0,sizeof(f));
memset(c,0,sizeof(c));
memset(tag,0,sizeof(tag));
}
inline bool nroot(int x){
return c[f[x]][0]==x||c[f[x]][1]==x;
}
inline void pushr(int x){
int t=lc;
lc=rc,rc=t;
tag[x]^=1;
}
inline void pushdown(int x){
if(tag[x]){
if(lc) pushr(lc);
if(rc) pushr(rc);
tag[x]=0;
}
}
void rotate(int x){
int y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k];
if(nroot(y))c[z][c[z][1]==y]=x;c[x][!k]=y;c[y][k]=w;
if(w)f[w]=y;f[y]=x;f[x]=z;
}
void splay(int x){
int y=x,z=0;
st[++z]=y;
while(nroot(y)) st[++z]=y=f[y];
while(z) pushdown(st[z--]);
while(nroot(x)){
y=f[x];z=f[y];
if(nroot(y))
rotate((c[y][0]==x)^(c[z][0]==y)?x:y);
rotate(x);
}
}
void access(int x){
for(int y=0;x;x=f[y=x])
splay(x),rc=y;
}
void makeroot(int x){
access(x);splay(x);
pushr(x);
}
int findroot(int x){
access(x);splay(x);
while(lc)pushdown(x),x=lc;
splay(x);
return x;
}
void split(int x,int y){
makeroot(x);
access(y);splay(y);
}
inline void link(int x,int y){
f[x]=y;
}
void cut(int x,int y){
makeroot(x);
if(findroot(y)==x&&f[y]==x&&!c[y][0]){
f[y]=c[x][1]=0;
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
init();
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=m;i++){
scanf("%d%d",&e[i].from,&e[i].to);
}
int l=1,r=1;
while(l<=m){
while(r<=m){
int u=e[r].from,v=e[r].to;
makeroot(u);
if(findroot(v)==u){
break;
}
link(u,v);
r++;
}
if(r==m+1){
for(int i=l;i<=m;i++)
R[i]=m+1;
break;
}
R[l]=r;
cut(e[l].from,e[l].to);
l++;
}
int ans=0;
while(q--){
int x,y;
scanf("%d%d",&x,&y);
int k1=(x^ans)%m+1;
int k2=(y^ans)%m+1;
x=min(k1,k2);
y=max(k1,k2);
if(y>=R[x]){
ans=1;
printf("Yes\n");
}
else{
ans=0;
printf("No\n");
}
}
}
return 0;
}
E
题意
解法
代码
//将内容替换成代码
F Fluctuation Limit
题意
给你一个n和k,给你n个价格范围l,r,问最后没组价格的上下浮动能不能不超过k。若可以,那么输出YES并输出他的价格序列;否则出NO。
解法
我们可以根据给定的第一个区间,推断第二个区间满足第二个条件的范围,也就是[l1 - x, r1 + x],然后再让这个区间和[l2,r2]区间取并集,那么得到的区间中的任何一个数字都是合法区间
代码
#pragma region
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <vector>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; ++i)
#define per(i, a, n) for (int i = n; i >= a; --i)
namespace fastIO {
#define BUF_SIZE 100000
#define OUT_SIZE 100000
//fread->R
bool IOerror = 0;
//inline char nc(){char ch=getchar();if(ch==-1)IOerror=1;return ch;}
inline char nc() {
static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
if (p1 == pend) {
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
if (pend == p1) {
IOerror = 1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch) { return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; }
template <class T>
inline bool R(T &x) {
bool sign = 0;
char ch = nc();
x = 0;
for (; blank(ch); ch = nc())
;
if (IOerror) return false;
if (ch == '-') sign = 1, ch = nc();
for (; ch >= '0' && ch <= '9'; ch = nc()) x = x * 10 + ch - '0';
if (sign) x = -x;
return true;
}
inline bool R(double &x) {
bool sign = 0;
char ch = nc();
x = 0;
for (; blank(ch); ch = nc())
;
if (IOerror) return false;
if (ch == '-') sign = 1, ch = nc();
for (; ch >= '0' && ch <= '9'; ch = nc()) x = x * 10 + ch - '0';
if (ch == '.') {
double tmp = 1;
ch = nc();
for (; ch >= '0' && ch <= '9'; ch = nc())
tmp /= 10.0, x += tmp * (ch - '0');
}
if (sign)
x = -x;
return true;
}
inline bool R(char *s) {
char ch = nc();
for (; blank(ch); ch = nc())
;
if (IOerror)
return false;
for (; !blank(ch) && !IOerror; ch = nc())
*s++ = ch;
*s = 0;
return true;
}
inline bool R(char &c) {
c = nc();
if (IOerror) {
c = -1;
return false;
}
return true;
}
template <class T, class... U>
bool R(T &h, U &... t) { return R(h) && R(t...); }
#undef OUT_SIZE
#undef BUF_SIZE
}; // namespace fastIO
using namespace fastIO;
template <class T>
void _W(const T &x) { cout << x; }
void _W(const int &x) { printf("%d", x); }
void _W(const int64_t &x) { printf("%lld", x); }
void _W(const double &x) { printf("%.16f", x); }
void _W(const char &x) { putchar(x); }
void _W(const char *x) { printf("%s", x); }
template <class T, class U>
void _W(const pair<T, U> &x) { _W(x.F), putchar(' '), _W(x.S); }
template <class T>
void _W(const vector<T> &x) {
for (auto i = x.begin(); i != x.end(); _W(*i++))
if (i != x.cbegin()) putchar(' ');
}
void W() {}
template <class T, class... U>
void W(const T &head, const U &... tail) { _W(head), putchar(sizeof...(tail) ? ' ' : '\n'), W(tail...); }
#pragma endregion
const ll maxn = 1e5 + 500;
const int mod=1e9+7;
ll gcd(ll T, ll b) { return b == 0 ? T : gcd(b, T % b); }
ll lcm(ll T, ll b) { return T / gcd(T, b) * b; }
ll mul(ll a,ll b, ll c) {
ll ans = 0;
while(b) {
if(b&1) {
ans= (ans+a)%c;
b--;
}
b>>=1;
a=(a+a)%c;
}
return ans;
}
ll powmod(ll a,ll b,ll c) {
ll ans = 1;
while(b) {
if(b&1) {
ans = mul(ans,a,c);
b--;
}
b>>=1;
a=mul(a,a,c);
}
return ans ;
}
struct node {
ll l, r;
} a[maxn];
int main() {
ll T;
// cin>>T;
scanf("%lld", &T);
while (T--) {
ll n, k;
// cin>>n>>k;
scanf("%lld%lld", &n, &k);
for (int i=1; i<=n; ++i) {
// cin>>a[i].l>>a[i].r;
scanf("%lld%lld", &a[i].l, &a[i].r);
}
bool flag=true;
for (int i=2; i<=n; ++i) {
ll l0 = a[i-1].l-k;
ll r0 = a[i-1].r+k;
a[i].l = max(l0, a[i].l);
a[i].r = min(r0, a[i].r);
if (a[i].l > a[i].r) {
flag=false;
break;
}
}
for (int i=n-1; i>=1; --i) {
ll l0 = a[i+1].l-k;
ll r0 = a[i+1].r+k;
a[i].l = max(l0, a[i].l);
a[i].r = min(r0, a[i].r);
if (a[i].l > a[i].r) {
flag=false;
break;
}
}
if (!flag) {
// cout<<"NO\n";
printf("NO\n");
} else {
// cout<<"YES\n";
printf("YES\n");
for (int i=1; i<=n; ++i) {
if(i!=n) {
// cout<<a[i].l<<" ";
printf("%lld ", a[i].l);
}
else {
// cout<<a[i].l<<"\n";
printf("%lld\n", a[i].l);
}
}
}
}
return 0;
}
G
题意
解法
代码
//将内容替换成代码
H Hexagon
题意
给出半径为n的六边形(由半径为1的小六边形组成),从某一个小六边形出发由六个方向,找到一条转向次数最多的路径(用方向表示)遍历所有的六边形(一个六边形只访问一次)。
解法
分别分成奇数和偶数的情况,然后奇数内三层都是一样的,特殊处理一下六边形出来的第一个边,还有六边形的最后一条边;偶数的内两层都是一样的,然后特殊处理一下六边形的最后一条边。每次加2层是加4步。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int INF=0x3f3f3f3f;
const double pi=acos(-1.0),eps=1e-8;
const ll mod = 998244353;
const int maxn=1e5+5;
struct node
{
double x,y;
} cir[5],p1,p2;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
if(n%2==0)
{
printf("461234");
if(n>2)
{
int num=5;
int xx=2;
while(xx<n)
{
printf("34");
int x=6,y=4;
for(int k=0; k<6; k++)
{
if(k<5)
{
for(int i=0; i<num; i++)
{
if(i%2==0)
printf("%d",x);
else
printf("%d",y);
}
}
else
{
for(int i=0; i<num-3; i++)
{
if(i%2==0)
printf("%d",x);
else
printf("%d",y);
}
}
x=(x)%6+1;
y=(y)%6+1;
}
printf("4");
num+=4;
xx+=2;
}
}
}
else
{
printf("546126231342453564");
if(n>3)
{
int num=7;
n-=2;
while(n>1)
{
printf("546");
int x=1,y=5;
for(int i=0; i<num-2; i++)
{
if(i%2==0)
printf("%d",x);
else
printf("%d",y);
}
x=(x)%6+1;
y=(y)%6+1;
for(int k=0; k<4; k++)
{
for(int i=0; i<num; i++)
{
if(i%2==0)
printf("%d",x);
else
printf("%d",y);
}
x=(x)%6+1;
y=(y)%6+1;
}
for(int i=0; i<num-1; i++)
{
if(i%2==0)
printf("%d",x);
else
printf("%d",y);
}
n-=2;
num+=4;
}
}
}
printf("\n");
}
return 0;
}
I Isomorphic Strings
题意
给一个长度为n的字符串,问能不能分解成k个字段,每个字段长度相同,而且字符串的最小表示相同。其中k要大于1。
输出yes和no
解法
要想成功分解成k段,那么最少每段的字符数量要相同,而且还要被n整除,所以找到所有字符和n的公约数len,n/len就是最小的k,
k每次可以增长一倍,然后判断能不能被n整除,然后判断每个字符串的不同种类就可以用map记录每一个的hash就行。
最后判断每一段的字符串hash值,在不在这些map已经记录的hash值中。
代码
#include<bits/stdc++.h>
#define emplace_back push_back
#define pb push_back
using namespace std;
typedef long long LL;
const LL mod = 13331;
const double eps = 1e-6;
const LL inf = 0x3f3f3f3f;
const LL N = 5e6 + 10;
LL num[30];
LL ha[N];
LL p[N];
char s[N];
map<LL, LL> mp;
int main()
{
p[0] = 1;
for (LL i = 1; i < N; i++)
{
p[i] = p[i - 1] * mod;
}
LL t;
scanf("%lld", &t);
while (t--)
{
LL n;
scanf("%lld", &n);
scanf("%s", s + 1);
memset(num, 0, sizeof(num));
ha[0] = 0;
for (LL i = 1; i <= n; i++)
{
num[s[i] - 'a' + 1]++;
ha[i] = ha[i - 1] * mod + (s[i] - 'a' + 1);
}
LL gg = n;
for (LL i = 1; i <= 26; i++)
{
if (num[i])
gg = __gcd(gg, num[i]);
}
LL u = n / gg;
LL flog = 1;
if (u == 1 && n != 1)
{
flog = 0;
}
else
{
for (LL i = 1; i < gg; i++)
{
LL len = i * u;
if(n%len)
{
continue;
}
flog = 0;
mp.clear();
LL k = ha[len] - ha[0] * p[len];
mp[k] = 1;
for (LL j = 1; j < len; j++)
{
k = k * mod + (s[j]-96);
mp[k - ha[j] * p[len]] = 1;
}
for (LL j = 1; j * len <= n; j++)
{
if (mp[ha[j * len] - ha[(j - 1) * len] * p[len]] == 0)
{
flog = 1;
break;
}
}
if (flog == 0)
{
break;
}
}
}
if (flog == 0)
{
printf("Yes\n");
}
else
{
printf("No\n");
}
}
return 0;
}
J
题意
解法
代码
//将内容替换成代码
K Kidnapper's Matching Problem
题意
给出两个数组A,B和集合S,分别有n,m,k个数
求题目中表达式 题目链接
解法
先求出S集合的线性基,然后对A,B集合中的数,消去对应线性基中的位。
则剩下的数如果想满足异或后在S集合中,必须相等。因为余下的位已经无法用线性基表示。
然后就变成了找A串中的B串,用KMP处理
代码
#include <bits/stdc++.h>
using namespace std;
int const maxn=2e5+7,mod=1e9+7;
const int MAXL = 29,maxn2=5e4+7;
int n,m,k,nex[maxn2];
bool res[maxn];
long long a[maxn],b[maxn2],s[maxn2];
struct LinearBasis{
long long aa[MAXL+1];
LinearBasis(){
std::fill(aa, aa + MAXL + 1, 0);
}
void insert(long long t){
for (int j = MAXL; j >= 0; j--){
if (!(t & (1ll << j))) continue;
if (aa[j]) t ^= aa[j];
else
{
for (int k = 0; k < j; k++) if (t & (1ll << k)) t ^= aa[k];
for (int k = j + 1; k <= MAXL; k++) if (aa[k] & (1ll << j)) aa[k] ^= t;
aa[j] = t;
return;
}
}
}
void build(long long *x, int len){
std::fill(aa, aa + MAXL + 1, 0);
for (int i = 1; i <= len; i++){
insert(x[i]);
}
}
}ji;//线性基模板
int main(){
int t;
scanf("%d",&t);
for(int q=1;q<=t;q++){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
for(int i=1;i<=m;i++){
scanf("%lld",&b[i]);
}
for(int i=1;i<=k;i++){
scanf("%lld",&s[i]);
}
ji.build(s,k);
for(int i=1;i<=n;i++){
for(int j=MAXL;j>=0;j--)if(a[i]>>j&1)a[i]^=ji.aa[j];
}
for(int i=1;i<=m;i++){
for(int j=MAXL;j>=0;j--)if(b[i]>>j&1)b[i]^=ji.aa[j];
}
long long ans=0;
nex[1]=0;
for(int i=2,j=0;i<=m;i++){
while(j&&b[j+1]!=b[i])j=nex[j];
if(b[j+1]==b[i])j++;
nex[i]=j;
}
memset(res,0,n);
for(int i=1,j=0;i<=n;i++){
while(j&&b[j+1]!=a[i])j=nex[j];
if(b[j+1]==a[i])j++;
if(j==m){
res[i-m]=1;
j=nex[j];
}
}
for(int i=n-m;i>=0;i--)ans=(ans*2+res[i])%mod;
printf("%lld\n",ans);
}
}

浙公网安备 33010602011771号