The 15th Heilongjiang Provincial Collegiate Programming Contest题解 gym102803

The 15th Heilongjiang Provincial Collegiate Programming Contest题解 gym102803

  • 前言
  • 题目
    • A. August
    • B. Bills of Paradise
    • C. Cornelia Street
    • D. Death by Thousand Cuts
    • F. False God
    • G. Goodbye
    • H. Hate That You Know Me
    • K. Keeping A Secret
    • L. Let's Get Married
  • 总结

前言

刚和队友组队,第一次一起vp,也为几天后的比赛做准备

题目

A. August

https://codeforces.com/gym/102803/problem/A

给定四条曲线,有两个参数,求包围的面积,其中有两条是圆,有两条是反三角函数(下面是样例的图)
The 15th Heilongjiang Provincial Collegiate Programming Contest题解 gym102803_第1张图片
圆面积直接求。反三角函数转成三角函数直接积分即可
队友代码:

#include
#define N
using namespace std;
bool cur1;
int n;
inline void Rd(int &res){
	char c;res=0;
	while(c=getchar(),c<48);
	do res=(res<<3)+(res<<1)+(c^48);
	while(c=getchar(),c>47);
	return;
}
bool cur2;
int main(){
//	printf("%lf MB\n",(&cur2-&cur1)/1024.0/1024);
//	freopen("data.txt","r",stdin);
	int T;
	Rd(T);
	while(T--){
		int a,b;
		Rd(a);Rd(b);
		double pi=acos(-1);
		printf("%lf\n",4.0*a*b+pi*a*a);
	}
	return 0;
}

B. Bills of Paradise

https://codeforces.com/gym/102803/problem/B
一眼数据结构,直接交给队友了
队友代码:

#include
#define N 1000005
using namespace std;
bool cur1;
int n,q;
unsigned long long k1, k2;
long long a[N];
inline unsigned long long xorShift128Plus() {
    unsigned long long k3 = k1, k4 = k2;
    k1 = k4;
    k3 ^= k3 << 23;
    k2 = k3 ^ k4 ^ (k3 >> 17) ^ (k4 >> 26);
    return k2 + k4;
}
inline void Rd(int &res){
	char c;res=0;
	while(c=getchar(),c<48);
	do res=(res<<3)+(res<<1)+(c^48);
	while(c=getchar(),c>47);
	return;
}
inline int get1(long long x){
	int l=1,r=n,res=-1;
	while(l<=r){
		int mid=(l+r)>>1;
		if(a[mid]>=x)res=mid,r=mid-1;
		else l=mid+1;
	}
	return res;
}
inline int get2(long long x){
	int l=1,r=n,res=-1;
	while(l<=r){
		int mid=(l+r)>>1;
		if(a[mid]<=x)res=mid,l=mid+1;
		else r=mid-1;
	}
	return res;
}
struct YDtree{
	#define ls p<<1
	#define rs p<<1|1
	bool hv[N<<2],flag[N<<2];
	long long sum[N<<2],len[N<<2];
	inline void up(int p){
		sum[p]=sum[ls]+sum[rs];
		hv[p]=hv[ls]|hv[rs];
	}
	inline void down(int p){
		if(flag[p]){
			flag[ls]=flag[rs]=1;
			hv[ls]=hv[rs]=1;
			sum[ls]=len[ls];
			sum[rs]=len[rs];
			flag[p]=0;
		}
	}
	void build(int l,int r,int p){
		if(l==r){
			sum[p]=len[p]=a[l];
			hv[p]=1;
			return;
		}
		int mid=(l+r)>>1;
		build(l,mid,ls);
		build(mid+1,r,rs);
		len[p]=len[ls]+len[rs];
		up(p);
	}
	long long quiry1(int l,int r,int L,int R,int p){
		if(!hv[p])return -1;
		if(l==r)return a[l];
		down(p);
		int mid=(l+r)>>1;
		if(!hv[ls]||mid<L)return quiry1(mid+1,r,L,R,rs);
		long long h=quiry1(l,mid,L,R,ls);
		if(h==-1){
			if(mid<R)return quiry1(mid+1,r,L,R,rs);
			return -1;
		}
		return h;
	}
	bool update2(int l,int r,int L,int R,int p){
		if(!hv[p])return false;
		if(l==r){
			sum[p]=0;
			hv[p]=0;
			return true;
		}
		down(p);
		bool res;
		int mid=(l+r)>>1;
		if(!hv[ls]||mid<L)res=update2(mid+1,r,L,R,rs);
		else{
			res=update2(l,mid,L,R,ls);
			if(!res){
				if(mid<R)res=update2(mid+1,r,L,R,rs);
			}
		}
		up(p);
		return res;
	}
	long long quiry3(int l,int r,int L,int R,int p){
		if(L<=l&&r<=R)return sum[p];
		down(p);
		int mid=(l+r)>>1;
		long long res=0;
		if(mid>=L)res=quiry3(l,mid,L,R,ls);
		if(mid<R)res+=quiry3(mid+1,r,L,R,rs);
		return res;
	}
	void update4(int l,int r,int L,int R,int p){
		if(L<=l&&r<=R){
			flag[p]=1;
			sum[p]=len[p];
			hv[p]=1;
			return;
		}
		down(p);
		int mid=(l+r)>>1;
		if(mid>=L)update4(l,mid,L,R,ls);
		if(mid<R)update4(mid+1,r,L,R,rs);
		up(p);
	}
}YD;
bool cur2;
int main(){
//	printf("%lf MB\n",(&cur2-&cur1)/1024.0/1024);
//	freopen("data.txt","r",stdin);
    scanf("%d %llu %llu", &n, &k1, &k2);
    for (int i = 1; i <= n; i++) a[i] = xorShift128Plus() % 999999999999 + 1;
	sort(a+1,a+n+1);
	YD.build(1,n,1);
	Rd(q);
	for(int i=1;i<=q;i++){
		char str[3];
		long long x;
		scanf("%s %lld",str,&x);
		if(str[0]=='F'){
			int h=get1(x);
			if(h==-1)puts("1000000000000");
			else{
				long long res=YD.quiry1(1,n,h,n,1);
				if(res==-1)puts("1000000000000");
				else printf("%lld\n",res);
			}
		}
		else if(str[0]=='D'){
			int h=get1(x);
			if(h==-1)continue;
			YD.update2(1,n,h,n,1);
		}
		else if(str[0]=='C'){
			int h=get2(x);
			if(h==-1)puts("0");
			else printf("%lld\n",YD.quiry3(1,n,1,h,1));
		}
		else{
			int h=get2(x);
			if(h==-1)continue;
			YD.update4(1,n,1,h,1);
		}
	}
	return 0;
}

C. Cornelia Street

https://codeforces.com/gym/102803/problem/C
给定一个字符串 S ( ∣ S ∣ ≤ 8 × 1 0 5 ) S(|S|\le8\times 10^5) S(S8×105),找到两个等长的串 A A A B B B, 使得 S = A A … A B B … B A A … A a S=AA\dots ABB\dots BAA\dots Aa S=AAABBBAAAa,其中 a a a A A A 的一个前缀(可以为空),最小化 ∣ A ∣ |A| A

枚举 ∣ A ∣ |A| A,找到第一个不匹配的位置,即为 B B B,同样的操作找到连续 B B B 串的结尾,后面判断是否全为 A A A 。判断相等用 h a s h hash hash 即可,复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn) log ⁡ n \log n logn 是调和级数
代码:

#include
/*
#include
#include
#include
#include
#include
#include
#include
//*/
using namespace std;
typedef long long ll;
typedef double db;
const int N=1000010,M=1000010,P=1e9+7;
const int p1=1e9+9,p2=998244353;
const int inf=0x3f3f3f3f;
const int INF=0xcfcfcfcf;
const db eps=1e-9,pi=2*asin(1);
template<typename tn> void read(tn &n);
template<typename tn1,typename tn2> bool cmax(tn1 &x,tn2 y) { return x<y?x=y,true:false; }
template<typename tn1,typename tn2> bool cmin(tn1 &x,tn2 y) { return x>y?x=y,true:false; }
#define mp(x,y) make_pair(x,y)
#define pii pair<int,int>
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pll pair<ll,ll>
int ADD(int x,int y,int p=P) { return x+y>=p?x+y-p:x+y; }
int MINUS(int x,int y,int p=P) { return x-y<0?x-y+p:x-y; }
#define plus(a,b) a=ADD(a,b)
#define minus(a,b) a=MINUS(a,b)
#define mul(a,b) a=1ll*(a)*(b)%P
#define mem(a,b) memset(a,b,sizeof(a))

int BASE=129;
int n;
int h1[N],h2[N];
int m1[N],m2[N];
char s[N];

void init()
{
	m1[0]=m2[0]=1;
	for(int i=1;i<=n;i++)
	{
		int ch=s[i]+1;
		h1[i]=(1ll*h1[i-1]*BASE+ch)%p1;
		h2[i]=(1ll*h2[i-1]*BASE+ch)%p2;
		m1[i]=1ll*m1[i-1]*BASE%p1;
		m2[i]=1ll*m2[i-1]*BASE%p2;
		// cerr<
	}
	// cerr<<"\n";
}
pii get(int l,int r)
{
	return mp(((h1[r]-1ll*h1[l-1]*m1[r-l+1])%p1+p1)%p1,((h2[r]-1ll*h2[l-1]*m2[r-l+1])%p2+p2)%p2);
}

template<typename tn> void read(tn &n)
{
	tn s=0,flag=1;
	char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') flag=-1;
	for(;'0'<=ch&&ch<='9';ch=getchar()) s=s*10+ch-'0';
	if(ch=='.')
	{
		ch=getchar();
		tn r=0,R=1;
		for(;'0'<=ch&&ch<='9';ch=getchar()) r=r*10+ch-'0',R*=10;
		s+=r/R;
	}
	n=s*flag;
}

int main()
{
	scanf("%s",s+1);
	// cerr<
	n=strlen(s+1);
	init();
	int stb;
	for(int i=1;i<=n;i++)
	{
		// cerr<
		pii a,b;
		a=get(1,i);
		int p=i+1;
		while(p+i-1<=n&&get(p,p+i-1)==a) p+=i;
		// cerr<
		// cerr<
		if(p+i-1>n&&get(p,n)==get(1,n-p+1))
		{
			for(int j=1;j<=i;j++) putchar(s[j]);
				putchar(' ');
			for(int j=p-i;j<=p-1;j++) putchar(s[j]);
				putchar('\n');
			return 0;
		}
		b=get(p,p+i-1),stb=p;
		// cerr<
		while(p+i-1<=n&&get(p,p+i-1)==b) p+=i;
		// cerr<
		// cerr<
		while(p+i-1<=n&&get(p,p+i-1)==a) p+=i;
		if(get(p,n)==get(1,n-p+1))
		{
			for(int j=1;j<=i;j++) putchar(s[j]);
				putchar(' ');
			for(int j=stb;j<=stb+i-1;j++) putchar(s[j]);
				putchar('\n');
			return 0;
		}
		// cerr<<"\n";
	}
	return 0;
}

D. Death by Thousand Cuts

https://codeforces.com/gym/102803/problem/D
给一个正方体和一个法向量确定的平面,求平面与长方体的棱的交点数量为3/4/5/6个的概率

就一个大讨论,分界点一定是长方体的顶点位于平面内的情况(队友nb!!!)
队友代码:

#include 
#include 
#include 

long long gcd(long long a, long long b) {
    return b ? gcd(b, a % b) : a;
}

const int P = int(1e9) + 7;

long long pow(long long a, long long b) {
    long long r = 1;
    while (b) {
        if (b & 1) r = r * a % P;
        b >>= 1;
        a = a * a % P;
    }
    return r;
}

long long int_inv(long long x) {
    return pow(x, P - 2);
}

/* a/b */
struct num {
    long long a, b;

    num(): a(0), b(1) {}
    num(long long t): a(t), b(1) {}
    num(long long a, long long b): a(a), b(b) {
        simp();
    }

    void read() {
        long long t;
        scanf("%lld", &t);
        *this = num(t);
    }

    long long print() {
        long long q = a, p = b;
        return 1ll * q * int_inv(p) % P;
    }

    void dump() {
        printf("%lld/%lld ", a, b);
    }

    void simp() {
        if (b < 0) {
            a = -a;
            b = -b;
        }
        long long g = gcd(a, b);
        a /= g;
        b /= g;
    }

    num operator-() {
        return num(-a, b);
    }

    num inv() {
        return num(b, a);
    }

    friend num operator+(num x, num y) {
        return num(
            x.a * y.b + x.b * y.a,
            x.b * y.b
        );
    }

    friend num operator-(num x, num y) {
        return x + -y;
    }

    friend num operator*(num x, num y) {
        return num(
            x.a * y.a,
            x.b * y.b
        );
    }

    friend num operator/(num x, num y) {
        return x * y.inv();
    }

    friend bool operator==(num x, num y) {
        return x.a == y.a && x.b == y.b;
    }

    friend bool operator<(num x, num y) {
        num z = x - y;
        if (z.a == 0) return false;
        return (z.a < 0) ^ (z.b < 0);
    }

    friend bool operator<=(num x, num y) {
        return x < y || x == y;
    }

    bool in_0_1() {
        return a >= 0 && a <= b;
    }
};

int T;
num a, b, c, A, B, C;

num _; // zero

num ans[10]; // ans[3..6];

std::vector<num> v;

num solve_d(num x, num y, num z) {
    return -(A * x + B * y + C * z);
}

// int is_cross(num D, num x0, num y0, num z0, num dx, num dy, num dz) {
//     // x = dx*t + x0 ...

//     // A * (dx*t + x0) + ... + D == 0

//     // num t = -(
//     //     (D + A*x0 + B*y0 + C*z0) / (A * dx + B * dy + C * dz)
//     // );

//     return (-((D + A*x0 + B*y0 + C*z0) / (A * dx + B * dy + C * dz))).in_0_1();
// }

#define is_cross(D, x0, y0, z0, dx, dy, dz) ((-((D + A*x0 + B*y0 + C*z0) / (A * dx + B * dy + C * dz))).in_0_1())

int main() {
    scanf("%d", &T);
    while (T--) {
        a.read();
        b.read();
        c.read();
        A.read();
        B.read();
        C.read();

        v.clear();
        v.push_back(solve_d(_, _, _));
        v.push_back(solve_d(_, _, c));
        v.push_back(solve_d(_, b, _));
        v.push_back(solve_d(_, b, c));
        v.push_back(solve_d(a, _, _));
        v.push_back(solve_d(a, _, c));
        v.push_back(solve_d(a, b, _));
        v.push_back(solve_d(a, b, c));
        std::sort(v.begin(), v.end());

        // for (auto &z : v) {
        //     z.dump();
        //     printf("\n");
        // }

        for (int i = 3; i <= 6; i++) {
            ans[i] = num(0);
        }

        num minD = v[0], maxD = v[7];

        for (int i = 0; i <= 6; i++) {
            int j = i + 1;

            if (v[i] == v[j]) continue;

            num D = (v[i] + v[j]) / num(2);

            int cross = 0;

            cross += is_cross(D, _, _, _, a, _, _);
            cross += is_cross(D, _, _, _, _, b, _);
            cross += is_cross(D, a, _, _, _, b, _);
            cross += is_cross(D, _, b, _, a, _, _);

            cross += is_cross(D, _, _, _, _, _, c);
            cross += is_cross(D, a, _, _, _, _, c);
            cross += is_cross(D, _, b, _, _, _, c);
            cross += is_cross(D, a, b, _, _, _, c);

            cross += is_cross(D, _, _, c, a, _, _);
            cross += is_cross(D, _, _, c, _, b, _);
            cross += is_cross(D, a, _, c, _, b, _);
            cross += is_cross(D, _, b, c, a, _, _);

            // printf("D=[");
            // v[i].dump();
            // printf("..");
            // v[j].dump();
            // printf("] (avg=");
            // D.dump();
            // printf(") cross=%d\n", cross);

            ans[cross] = ans[cross] + (v[j] - v[i]) / (maxD - minD);
        }

        printf("%lld %lld %lld %lld\n", ans[3].print(), ans[4].print(), ans[5].print(), ans[6].print());
    }
}

F. False God

https://codeforces.com/gym/102803/problem/F
回合制游戏,每回合你先动。对面有 n ( n ≤ 1000 ) n(n\le 1000) n(n1000) 颗棋子,每回合都会朝前(你)移动一步。你有一颗棋子,每回合可以向前/后/左/右/左前/右前移动一步。求你最多可以吃掉几颗对面的棋子

首先先简化操作。我们发现在正常情况下后退是没用的,因为你不会走到一颗棋子的后面,不然你上一回合就已经把它吃掉了(除非初始情况,一开始判断掉),这样你就不会后退了。
然后可以发现,我们一定是优先横向移动棋子,因为对方棋子的相对位置是不变的,所以我们没必要向前主动地去吃棋子,等对面送上来就行了。
这样就有一个问题,我们每回合必须得移动棋子,不能停在原地,这有点难受。我们可以花两回合停在原地,即先左再右,想要做到一回合不动还是不行,但我们可以替换掉原来的横向移动操作,以向左为例,我们可以先向左前再向后,这样原本一步向左变成了两步向左,实现了一步停留,向前、向右同理。
最后,按照上述的结论,越靠前的棋子越先被吃, d p dp dp 即可。复杂度 O ( n 2 ) O(n^2) O(n2)
队友代码:

#include 
#include 
#include 

#define REP(i, n) for (int i = 0; i < n; i++)

#define pii std::pair<int, int>
#define xx first
#define yy second

const int N = 1003;

int T, xx0, yy0, n;
pii p[N];

int f[N];


int cmp(pii &a, pii &b) {
    if (a.yy != b.yy) return b.yy > a.yy;
    return b.xx > a.xx;
}

int main() {
    scanf("%d", &T);
    while (T--) {
        memset(f, 0x87, sizeof f);

        scanf("%d%d%d", &xx0, &yy0, &n);
        int tag = 0;
        REP(i, n) {
            scanf("%d%d", &p[i].xx, &p[i].yy);
            tag |= p[i].xx == xx0 && p[i].yy == yy0-1;
        }
        if (!tag) {
            p[n].xx = xx0;
            p[n].yy = yy0-1;
            n++;
        }
        std::sort(p, p+n, cmp);

        int ans = 0;

        pii *pp = std::find(p, p + n, pii{xx0, yy0-1});
        if (tag) {
            f[pp-p]=1;
            // printf("%d,%d :: 1\n", xx0, yy0-1);
        } else {
            f[pp-p]=0;
            // printf("%d,%d :: 0\n", xx0, yy0-1);
        }

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < i; j++) {
                if (p[j].yy > p[i].yy) continue;
                if (p[j].yy == p[i].yy) continue;
                if (abs(p[i].xx - p[j].xx) > p[i].yy - p[j].yy + 1) continue;
                // printf("+ %d,%d -> %d,%d :: %d\n", p[j].xx, p[j].yy, p[i].xx, p[i].yy, f[j]+1);
                if (f[j]+1 > f[i]) {
                    f[i] = f[j]+1;
                }
                ans = std::max(ans, f[i]);
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

G. Goodbye

https://codeforces.com/gym/102803/problem/G
两个人玩游戏。给定一个 n ( n ≤ 1 0 5 ) n(n\le10^5) n(n105),每次操作可以取一个当前数的非平凡因子(非 1 1 1 和本身的因子,题目中说的真因子,但给的定义是对的)替代当前数,不能操作的人获胜,问先手是否获胜,如果获胜输出应该取的最大的数(直接获胜输出 0 0 0)。多测 T ≤ 1 0 3 T\le 10^3 T103

脑筋急转弯,暴力预处理即可,复杂度 O ( n n ) O(n\sqrt n) O(nn )
队友代码:

#include
#define N 233333
using namespace std;
bool cur1;
int n;
inline void Rd(int &res){
	char c;res=0;
	while(c=getchar(),c<48);
	do res=(res<<3)+(res<<1)+(c^48);
	while(c=getchar(),c>47);
	return;
}
int val[N];
void init(){
	int h=100000;
	for(int i=2;i<=h;i++){
		int cnt=0;
		val[i]=-1;
		for(int j=2;j*j<=i;j++)if(i%j==0){
			cnt++;
			if(val[j]==-1)val[i]=max(val[i],j);
			if(val[i/j]==-1)val[i]=max(val[i],i/j);
		}
		if(!cnt)val[i]=0;
	}
}
bool cur2;
int main(){
//	printf("%lf MB\n",(&cur2-&cur1)/1024.0/1024);
//	freopen("data.txt","r",stdin);
	init();
	int T;
	Rd(T);
	while(T--){
		Rd(n);
		printf("%d\n",val[n]);
	}
	return 0;
}

H. Hate That You Know Me

https://codeforces.com/gym/102803/problem/H
σ k ( n ) = ∑ d ∣ n d k \sigma_k(n)=\sum_{d|n}d^k σk(n)=dndk
给定 0 ≤ a , b < 4 ,    1 ≤ n ≤ 1 0 12 0\le a,b<4,\;1\le n\le 10^{12} 0a,b<4,1n1012,求
( ( ∑ i = 1 n σ a ( i ) ) ⊕ ( ∑ i = 1 n σ b ( i ) ) ) m o d    2 64 ((\sum_{i=1}^n\sigma_a(i))\oplus(\sum_{i=1}^n\sigma_b(i)))\mod 2^{64} ((i=1nσa(i))(i=1nσb(i)))mod264

眼瞎把 < < < 看成 ≤ \le ,导致队友推了一个四次方前缀和的通项(**出题人),浪费了好长时间(就说怎么那么多人会四次方前缀和的通项的)
⊕ \oplus 两边的式子一样,只推一个即可
∑ i = 1 n σ k ( i ) = ∑ i = 1 n ∑ d ∣ i d k = ∑ d = 1 n d k ∑ d ∣ i 1 = ∑ d = 1 n d k ⋅ ⌊ n d ⌋ \begin{aligned}\sum_{i=1}^n\sigma_k(i)&=\sum_{i=1}^n\sum_{d|i}d^k\\&=\sum_{d=1}^nd^k\sum_{d|i}1\\&=\sum_{d=1}^nd^k\cdot\lfloor\frac{n}{d} \rfloor \end{aligned} i=1nσk(i)=i=1ndidk=d=1ndkdi1=d=1ndkdn
一个整除分块再加一个 0 / 1 / 2 / 3 0/1/2/3 0/1/2/3 次方前缀和就做完了
队友代码:(可能写法有点不太一样)

#include
#define ull unsigned long long
using namespace std;
bool cur1;
long long n;
inline void Rd(int &res){
	char c;res=0;
	while(c=getchar(),c<48);
	do res=(res<<3)+(res<<1)+(c^48);
	while(c=getchar(),c>47);
	return;
}
ull solve0(ull l,ull r){return r-l+1;}
ull calc1(ull a){
	if(a&1)return (a+1)/2*a;
	return a/2*(a+1);
}
ull solve1(ull l,ull r){
	return calc1(r)-calc1(l-1);
}
ull calc2(ull a){
	ull h1=a,h2=a+1,h3=2*a+1;
	if(h1&1)h2>>=1;
	else h1>>=1;
	if(h1%3==0)h1/=3;
	else if(h2%3==0)h2/=3;
	else h3/=3;
	return h1*h2*h3;
}
ull solve2(ull l,ull r){
	return calc2(r)-calc2(l-1);
}
ull calc3(ull a){
	return calc1(a)*calc1(a);
}
ull solve3(ull l,ull r){
	return calc3(r)-calc3(l-1);
}
ull solve(ull l,ull r,int f){
	if(f==0)return solve0(l,r);
	if(f==1)return solve1(l,r);
	if(f==2)return solve2(l,r);
	if(f==3)return solve3(l,r);
}
bool cur2;
int main(){
//	printf("%lf MB\n",(&cur2-&cur1)/1024.0/1024);
//	freopen("data.txt","r",stdin);
	int a,b;
	scanf("%d%d%lld",&a,&b,&n);
	ull md=sqrt(n);
	ull res1=0,res2=0;
	for(int i=1;1ll*i*i<=n;i++){
		res1+=solve(i,i,a)*(n/i);
		res2+=solve(i,i,b)*(n/i);
		ull r=n/i,l=n/(i+1)+1;
		l=max(l,(ull)(i+1));
		res1+=solve(l,r,a)*i;
		res2+=solve(l,r,b)*i;
//		printf("%d %llu %llu\n",i,l,r);
//		printf("%d %llu %llu\n",i,res1,res2);
	}
//	printf("%llu %llu\n",res1,res2);
	printf("%llu\n",res1^res2);
	return 0;
}

K. Keeping A Secret

https://codeforces.com/gym/102803/problem/K
有一棵树,给定所有点深度 d d d b f s bfs bfs 序的排名区间 [ 1 , x ] [1,x] [1,x],求有多少颗满足限制的树

(算法是我后来yy出来的,可能和代码不太一样)
首先, b f s bfs bfs 序是按深度排的,可以先算出每个深度的标号范围,层内的标号互不影响。
其次,层间的父子关系和层内的标号可以分开计算(父子关系插个板就好了)。
最后,层内可以按 x x x 从小到大排序后一个个安排即可
队友代码:

#include
#define N 100005
#define mod 1000000007
using namespace std;
bool cur1;
int n;
struct node{
	int d,x;
}Q[N];
inline bool cmp(node a,node b){
	return a.d==b.d?a.x<b.x:a.d<b.d;
}
inline void Rd(int &res){
	char c;res=0;
	while(c=getchar(),c<48);
	do res=(res<<3)+(res<<1)+(c^48);
	while(c=getchar(),c>47);
	return;
}
long long fac[N],infac[N];
inline long long C(int x,int y){
	return fac[y]*infac[x]%mod*infac[y-x]%mod;
}
void init(){
	fac[0]=infac[1]=infac[0]=1;
	for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
	for(int i=2;i<=n;i++)infac[i]=mod-mod/i*infac[mod%i]%mod;
	for(int i=2;i<=n;i++)infac[i]=infac[i]*infac[i-1]%mod;
}
bool cur2;
int main(){
//	printf("%lf MB\n",(&cur2-&cur1)/1024.0/1024);
//	freopen("data.txt","r",stdin);
	Rd(n);
	init();
	for(int i=1;i<=n;i++)Rd(Q[i].d),Rd(Q[i].x);
	sort(Q+1,Q+n+1,cmp);
	if((Q[1].d==1&&Q[2].d==1)||Q[1].d!=1){puts("0");return 0;}
	long long ans=1;
	for(int i=1,r,last=1;i<=n;i=r+1){
		r=i;
		while(r<n&&Q[r+1].d==Q[i].d)r++;
		if(i==1)continue;
		for(int j=i;j<=r;j++){
			int o=min(Q[j].x-j+1,r-j+1);
			if(o<1){
				puts("0");return 0;
			}
			ans=ans*o%mod;
		}
		ans=ans*C(last-1,r-i+last)%mod;
		last=r-i+1;
	}
	printf("%lld\n",ans);
	return 0;
}

L. Let’s Get Married

https://codeforces.com/gym/102803/problem/L
( 0 , 0 ) (0,0) (0,0) 为起点 b f s bfs bfs,每个点的编号为 b f s bfs bfs 序,求给定 b f s bfs bfs 序对应的点坐标或给定点坐标对应的 b f s bfs bfs 序,强制在线,多测 T ≤ 1 0 4 T\le 10^4 T104

(Due to some zz reason, WA/T了4发)
按哈密顿距离分层,每层 4 n 4n 4n 个( n n n 为哈密顿距离)。层内顺序为上左(第一象限),上右(第二象限),右下(第四象限),下左(第三象限)。
给定 b f s bfs bfs 序找层的时候要二分(别问我怎么知道的)
代码:

#include
/*
#include
#include
#include
#include
#include
#include
#include
//*/
using namespace std;
typedef long long ll;
typedef double db;
const int N=100010,M=1000010,P=1e9+7;
const int inf=0x3f3f3f3f;
const int INF=0xcfcfcfcf;
const db eps=1e-9,pi=2*asin(1);
template<typename tn> void read(tn &n);
template<typename tn1,typename tn2> bool cmax(tn1 &x,tn2 y) { return x<y?x=y,true:false; }
template<typename tn1,typename tn2> bool cmin(tn1 &x,tn2 y) { return x>y?x=y,true:false; }
#define mp(x,y) make_pair(x,y)
#define pii pair<int,int>
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pll pair<ll,ll>
int ADD(int x,int y,int p=P) { return x+y>=p?x+y-p:x+y; }
int MINUS(int x,int y,int p=P) { return x-y<0?x-y+p:x-y; }
#define plus(a,b) a=ADD(a,b)
#define minus(a,b) a=MINUS(a,b)
#define mul(a,b) a=1ll*(a)*(b)%P
#define mem(a,b) memset(a,b,sizeof(a))

template<typename tn> void read(tn &n)
{
	tn s=0,flag=1;
	char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') flag=-1;
	for(;'0'<=ch&&ch<='9';ch=getchar()) s=s*10+ch-'0';
	if(ch=='.')
	{
		ch=getchar();
		tn r=0,R=1;
		for(;'0'<=ch&&ch<='9';ch=getchar()) r=r*10+ch-'0',R*=10;
		s+=r/R;
	}
	n=s*flag;
}

int main()
{
	int n; read(n);
	ll xc=0,yc=0;
	for(int i=1;i<=n;i++)
	{
		int opt; read(opt);
		if(opt==1)
		{
			ll id; read(id);
			if(id==0)
			{
				printf("%lld %lld\n",-xc,-yc);
				xc=0,yc=0;
				continue;
			}
			ll x,y;
			ll l=0,r=5e8;
			while(l+1<r)
			{
				ll mid=l+r>>1;
				if(2ll*mid*(mid+1)<id) l=mid;
				else r=mid;
			}
			ll p=l+1;
			id-=2ll*p*(p-1);
			// cerr<<" "<
			if(1<=id&&id<=2*p-1) // up + ?
			{
				if(id==1)
				{
					x=p,y=0;
				}
				else
				{
					if(id&1) x=-id/2,y=p-id/2;
					else x=id/2,y=p-id/2;
				}
			}
			else if(2*p<=id&&id<=3*p-1) // right + down
			{
				id-=2*p;
				x=p-id,y=-id;
			}
			else if(3*p<=id&&id<=4*p) // down + left
			{
				id-=3*p;
				x=-id,y=id-p;
			}
			printf("%lld %lld\n",x-xc,y-yc);
			xc=x,yc=y;
		}
		else
		{
			ll x,y; read(x),read(y);
			ll p=abs(x)+abs(y);
			if(x==0&&y==0)
			{
				printf("0\n");
				xc=0,yc=0;
				continue;
			}
			ll ans=2ll*p*(p-1);
			if(y>0)
			{
				if(x==0) ans++;
				else if(x>0) ans+=2*x;
				else if(x<0) ans+=2*(-x)+1;
			}
			else if(x>0&&y<=0)
			{
				ans+=2*p-y;
			}
			else if(x<=0&&y<=0)
			{
				ans+=3*p-x;
			}
			printf("%lld\n",ans);
			xc=x,yc=y;
		}
	}
	return 0;
}
/*
1
2 -1 -1
*/
/*
1
1 79999999800000000
*/

总结

5h的比赛实际打了3h,由于只是队友之间的磨合,后面剩下三道难题都没花时间去做。
总结就是:队友nb!!!(有队友做大代码手就是爽)

你可能感兴趣的:(ACM,c++,算法,几何学)