多校9

A
贪心走最小的点,然后判环,如果走到一个环,就需要将与环有关的链全部废掉,因为这些节点一定有更优解
到这里可以\(O(n^3)\)水过
然后考虑有\(O(n^2)\)条路径,如何查询,如果对前驱建出一课路径树,询问本质上就是球一个点的dep = k的祖先。倍增即可做到\(O(n^2logn)\)
将询问离线下来,每次\(O(n)\)处理路径,\(O(nlogn)\)处理倍增,即可\(O(logn)\)处理每个询问

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int N = 3000+10, E = (5000+10)*2, Q = 4e5+10;
int n, m , q;
struct graph{
	vector<int> e[E];
	bool inq[N];
	void inse(int frm, int to){
		e[frm].push_back(to);
	}
	int pre[N][N];
	bool vis[N], inc[N];//inc:在环上
	int top;//环顶部
	bool ban[N];
	void dfs(int s, int u){
		inc[u] = true;
		for(int v : e[u]){
			if(inc[v]){
				top = v;
				break;
			}else if(!ban[v]){
				pre[s][v] = u;
				dfs(s, v);
			}
			if(top || ban[u]){
				break;
			}
		}
		if(top || ban[u]){
			fail(u);
		}
		if(u == top) top = 0;
		inc[u] = false;
		ban[u] = true;
	}
	void fail(int u){
		if(ban[u]) return;
		ban[u] = true;
		for(int v : e[u]){
			fail(v);
		}
	}
	void get(int s){
		top = 0;
		memset(inc, 0, sizeof(inc));
		memset(ban, 0, sizeof(ban));
		dfs(s, s);
	}
}G;
struct tree{
	struct edge{
		int nxt, to;
	}e[E];
	int head[N], elen;
	void inse(int frm, int to){
		e[++elen] = {head[frm], to};
		head[frm] = elen;
	}
	static const int RG = 16;
	int dep[N], fat[N][20];
	void clear(){
		memset(fat, 0, sizeof(fat));
		memset(dep, 0, sizeof(dep));
		memset(head, 0, sizeof(head));
		elen = 0;
	}
	void dfs1(int u){
		dep[u] = dep[fat[u][0]] + 1;
		for(int i = head[u]; i;i = e[i].nxt){
			int v = e[i].to;
			if(v == fat[u][0]) continue;	
			fat[v][0] = u;
			dfs1(v);
		}	
	}
	void init(){
		for(int j = 1; j <=RG; ++j){
			for(int i = 1; i <= n; ++i){
				fat[i][j] = fat[fat[i][j-1]][j-1];
			}
		}
	}
	int get(int u, int x){//u的dep=x父亲
		if(x > dep[u]) return -1;
		int dt = dep[u] - x;
		int ret = u;
		for(int i = 0; i <= RG; ++i){
			if(((1 <<(i))& dt)) ret = fat[ret][i];
		}
		return ret;
	}
}T;
struct t_q{
	int u, v, k, id;
};
vector<t_q> querys[N];
int ans[Q];
int main(){
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	cin >> n >> m >> q;
	for(int i = 1; i <= m;++i){
		int u, v;
		cin >> u >> v;
		G.inse(u, v);
	}
	for(int i = 1; i <= n; ++i){
		sort(G.e[i].begin(), G.e[i].end());
		G.e[i].erase(unique(G.e[i].begin(), G.e[i].end()), G.e[i].end());
	}
	for(int i= 1; i <= q; ++i){
		int u, v, k;
		cin >> u >> v >> k;
		querys[u].push_back({u, v, k, i});
	}
	for(int i = 1;i <= n; ++i){
		if(!querys[i].size()) continue;
		G.get(i);
		T.clear();
		for(int j = 1; j <= n; ++j){
			if(G.pre[i][j]) T.inse(G.pre[i][j], j);
		}
		T.dfs1(i);
		T.init();
		for(t_q ask : querys[i]){
			if(T.dep[ask.v]) {
				ans[ask.id] = T.get(ask.v, ask.k);
			}else{
				ans[ask.id] = -1;
			}
		}
	}
	for(int i = 1; i <= q; ++i){
		cout << ans[i] <<"\n";
	}
	return 0;
}

B
考场上SB了,这么SB的题直接跳了,5min拿20pts暴力分
一个数可以通过乘上他的最小奇质数因子,得到最小平方数,一个最小平方数可以乘上一个平方数得到一个平方数

#include<bits/stdc++.h>
using namespace std;
const int N = 2e6+10;
bool npri[N];
int pri[N];
int num[N];
int n, m;
void sieve(int len){
	for(int i = 2; i <= len; ++i){
		if(!npri[i]) pri[++pri[0]] = i,	num[i] = i;
		for(int j = 1; j <= pri[0] && pri[j] * i <= len; ++j){
			npri[i * pri[j]] = true;
			if(i % pri[j] == 0){
				num[i * pri[j]] = num[i];
				break;
			}
			num[i * pri[j]] = pri[j];
		}
	}
}
int d[N];
int sqr[N];
void split(int x){
	int rw = x;
	d[x] = 1;
	while(x != 1){
		int cnt = 0;
		int div = num[x];
		while(x % div == 0) x /= div, ++cnt;
		if(cnt & 1) d[rw] = d[rw] * div;
	}
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	sieve(2e6+10);;
	cin >> n >> m;
	for(int i = 1; i <= n; ++i){
		split(i);
	}
	int bound = ceil(sqrt(m));
	for(int i = 1; i <= bound; ++i){
		sqr[i] = i * i;
	}
	int ans = 0;
	for(int i = 1; i <= n; ++i){
		int lim = floor(1.0*m/d[i]);
		int pos = upper_bound(sqr + 1, sqr + 1 + bound, lim) - sqr-1;
		ans = ans + pos;
	}
	cout << ans << endl;
	return 0;
}

C
略(不想写正解,吉司机yyds!)
D
第一眼非常小清新的数位dp
然而需要高精度
学习了一种极限卡常方式
用unsigned long long 压17位,用const取模(编译器自动优化)
减少乘法,用加法替换乘法

#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 500+10, K = 15;
typedef unsigned long long ull;
struct big{
    static const int L = 60, BIT = 17;
    static const ull MOD = 1E17;
    ull a[L];
    big(){
        clear();
    }
    void clear(){
        memset(a, 0, sizeof(a));
    }
    void set0(){
        for(int i = 1; i <= a[0]; ++i) a[i] = 0;
    }
    bool is0(){
        return a[0] == 1 && a[1] == 0;
    }
    void init(const char str[]){
        int len = strlen(str + 1);
        a[0] = ceil(1.0 * len /BIT);
        for(int i = 1; i <= len; ++i){
            int j= ceil(1.0 * (len - i + 1)/ BIT);
            a[j] = a[j] * 10 + str[i] - '0';
        }
    }
    big(int x){
        clear();
        init(x);
    }
    big(const char str[]){
        clear();
        init(str);
    }
    void init(int x){
        a[1] = x;
        a[0] = 1;
    }
    friend big operator +(const big&a ,const big& b){
        big c;
        c.a[0] = max(a.a[0], b.a[0]);
        for(int i = 1; i <= c.a[0]; ++i){
            c.a[i] = a.a[i] + b.a[i];
        }
        for(int i = 1; i <= c.a[0]; ++i){
			c.a[i+1]+=c.a[i]/MOD,c.a[i]%=MOD;

        }
        if(c.a[c.a[0] + 1]) ++c.a[0];
        return c;
    }
	big operator +=(const big& b){
		a[0] = max(a[0], b.a[0]);
    	for(int i = 1; i <= a[0]; ++i){
            a[i] = a[i] + b.a[i];
        }
        for(int i = 1; i <= a[0]; ++i){
			a[i+1]+=a[i]/MOD,a[i]%=MOD;

        }
		if(a[a[0] + 1])	++a[0];
		return *this;
	}
    friend big operator *(const big& a, const int b){
        big c;
        c.a[0] = a.a[0];
        for(int i = 1; i <= a.a[0]; ++i){
        	c.a[i] = a.a[i] * b;
        }
        for(int i = 1; i <= c.a[0]; ++i){
            c.a[i + 1] += c.a[i] / MOD, c.a[i] %= MOD;
		}
        if(c.a[c.a[0] + 1]) ++c.a[0];
        while(c.a[0] > 1 && !c.a[c.a[0]]) --c.a[0];
        return c;
    }
    ull operator[](int x)const{
        return a[x];
    }
    ull& operator [](int x){
        return a[x];
    }
    void print(){
        printf("%llu", a[a[0]]);
        for(int i = a[0] - 1; i >= 1; --i){
            printf("%0*llu",BIT, a[i]);
        }
    }
};
big dp1[2][(1 << 10) + 10];
big dp2[2][(1 << 10) + 10];
big pw10, pwx;
int ban[K];
int nxt[(1 << 10) + 10];//状态的不可行状态
int n,m,k;
int main(){
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 1; i <= m; ++i){
        int u, v;
		scanf("%d%d", &u, &v);
        ban[u] |= 1 <<(v-1);//能否在后面添加
    }
    for(int i = 0; i < (1 << k); ++i){
        for(int j = 1; j <= k; ++j){
            if(i & (1 << (j-1))){
                nxt[i] |= ban[j];//i状态不能根j
            }
        }
    }
    dp1[0][0] = 1, dp2[0][0] = 0;
    for(int i = 0; i <= n; ++i){
        int d = i & 1;
        for(int j = 0; j < (1 << k); ++j)
            dp1[!d][j].set0(), dp2[!d][j].set0();
        for(int j = 0; j <(1 << k); ++j){
			if(dp1[d][j].is0()) continue;
			pw10 = dp2[d][j] *10, pwx = 0;
            for(int x = 1; x <= k; ++x){
				pwx += dp1[d][j];
                if(nxt[j] & (1 << (x-1))) continue;
                dp1[!d][j | (1 << (x-1))] += dp1[d][j];
                dp2[!d][j | (1 << (x-1))] += pw10 + pwx;
            }
        }
    }
    big ans1 = 0, ans2 = 0;
    for(int i = 0; i < (1 << k); ++i){
        ans1 += dp1[n & 1][i];
        ans2 += dp2[n & 1][i];
    }
    ans1.print();
    printf("\n");
    ans2.print();
    printf("\n");
    return 0;
}
posted @ 2022-08-03 21:20  CDsidi  阅读(16)  评论(0编辑  收藏  举报