2019nc#2
A Eddy Walker
题意
你有n个点(0~n-1),按顺序形成一个环,初始时你在0的位子,你随机顺时针走一步或者逆时针走一步,
一旦你走到一个点后,环上所有点都被经过至少一次后,你就必须停下来。
问你最后停留在m这个位子的概率是多少。
注意输出的答案是前缀积。
思路
有意思的概率题。
读懂题意后发现这道题不难,模拟下可以发现在最后落在(1~n-1)的位子是等概率的,落在0这个位子是不可能的(除非n==1)。
#include <iostream> #include <vector> #include <queue> #include <algorithm> using namespace std; #define pb push_back #define fi first #define se second #define debug(x) cerr<<#x << " := " << x << endl; #define bug cerr<<"-----------------------"<<endl; #define FOR(a, b, c) for(int a = b; a <= c; ++ a) typedef long long ll; typedef long double ld; typedef pair<int, int> pii; typedef pair<ll, ll> pll; template<class T> void _R(T &x) { cin >> x; } void _R(int &x) { scanf("%d", &x); } void _R(ll &x) { scanf("%lld", &x); } void _R(double &x) { scanf("%lf", &x); } void _R(char &x) { scanf(" %c", &x); } void _R(char *x) { scanf("%s", x); } void R() {} template<class T, class... U> void R(T &head, U &... tail) { _R(head); R(tail...); } template<typename T> inline T read(T&x){ x=0;int f=0;char ch=getchar(); while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x=f?-x:x; } const int inf = 0x3f3f3f3f; const int mod = 1e9+7; /**********showtime************/ ll ksm(ll a, ll b) { ll res = 1; while(b > 0) { if(b & 1) res = res * a % mod; a = a * a % mod; b = b >> 1; } return res; } int main(){ int T; scanf("%d", &T); ll res = 1; while(T--){ ll n,m; scanf("%lld%lld", &n, &m); if(n == 1 && m == 0) res = res; else { if(m == 0) res = res * 0; else { res = res * ksm(n-1, mod-2) % mod; } } printf("%lld\n", res); } return 0; }
B Eddy Walker 2
BM
D Kth Minimum Clique
题意:
在一个无向图中,找出一个权值为第K小的最小团,最小团的定义为选出的公共节点间有边直接联通。
思路:
感觉实现起来不太难。既然要选择第K小的,我们可以从小到大做。每次通过最小的一个最小团扩展,可以利用bitset优化判断扩展的可行性。
即利用优先队列,从其中取出的第k个就是答案。
有点像dji找最短路
#include<bits/stdc++.h> using namespace std; #define pb push_back #define fi first #define se second #define debug(x) cerr<<#x << " := " << x << endl; #define bug cerr<<"-----------------------"<<endl; #define FOR(a, b, c) for(int a = b; a <= c; ++ a) typedef long long ll; typedef long double ld; typedef pair<int, int> pii; typedef pair<ll, ll> pll; template<class T> void _R(T &x) { cin >> x; } void _R(int &x) { scanf("%d", &x); } void _R(ll &x) { scanf("%lld", &x); } void _R(double &x) { scanf("%lf", &x); } void _R(char &x) { scanf(" %c", &x); } void _R(char *x) { scanf("%s", x); } void R() {} template<class T, class... U> void R(T &head, U &... tail) { _R(head); R(tail...); } template<typename T> inline T read(T&x){ x=0;int f=0;char ch=getchar(); while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x=f?-x:x; } const int inf = 0x3f3f3f3f; const int mod = 1e9+7; /**********showtime************/ const int maxn = 109; char str[maxn]; struct node{ ll val; bitset<109>bs; bool operator<(const node & o) const{ return val > o.val; } }a[maxn]; int main(){ int n,k; scanf("%d%d", &n, &k); for(int i=1; i<=n; i++) { scanf("%lld", &a[i].val); } for(int i=1; i<=n; i++) { scanf("%s", str+1); for(int j=1; j<=n; j++) { if(str[j] == '1')a[i].bs.set(j); } } priority_queue<node>que; node s; s.val = 0; s.bs.reset(); que.push(s); int flag = 0;ll res; while(!que.empty()) { node u = que.top(); que.pop(); k -- ; if(k == 0) { flag = 1; res = u.val; break; } int mx = 1; for(int i=1; i<=n; i++) { if(u.bs[i] == 1) mx = i + 1; } for(int i=mx; i<=n; i++) { if((u.bs & a[i].bs) == u.bs) { u.bs.set(i); u.val += a[i].val; que.push(u); u.bs.reset(i); u.val -= a[i].val; } } } if(flag) printf("%lld\n", res); else puts("-1"); return 0; }
E MAZE
线段树,dp
F Partition problem
比赛时过的,双向搜索降低复杂度(队友搞的,我还没搞)
I Inside A Rectangle
dp
H Second Large Rectangle
比赛时过的。DP出面积,找出次大的
(队友搞的,我还没搞)
J Subarray
题意:
有一个长度为1E9,值为{-1,1}的数组,保证只有n(<1e6)个区间等于1,且1的个数小于1e7。
求有多少对区间的区间和大于0。
思路:
首先把被答案区间所包含的点都找出来。最多只有3e7个点。怎么找?
从小到达遍历数组,把每个区间向右扩展的长度找出来,
从大到小遍历数组,把每个区间向左扩展的长度找出来。
然后计算每个点的前缀和。在一个点前面且前缀和小于当前点的前缀和的一个点对应ans++。
由于前缀和的变化大小为1,所以不用树状数组即可完成。
#include <bits/stdc++.h> using namespace std; #define pb push_back #define fi first #define se second #define debug(x) cerr<<#x << " := " << x << endl; #define bug cerr<<"-----------------------"<<endl; #define FOR(a, b, c) for(int a = b; a <= c; ++ a) typedef long long ll; typedef long double ld; typedef pair<int, int> pii; typedef pair<ll, ll> pll; template<class T> void _R(T &x) { cin >> x; } void _R(int &x) { scanf("%d", &x); } void _R(ll &x) { scanf("%lld", &x); } void _R(double &x) { scanf("%lf", &x); } void _R(char &x) { scanf(" %c", &x); } void _R(char *x) { scanf("%s", x); } void R() {} template<class T, class... U> void R(T &head, U &... tail) { _R(head); R(tail...); } template<typename T> inline T read(T&x){ x=0;int f=0;char ch=getchar(); while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x=f?-x:x; } const int inf = 0x3f3f3f3f; const ll inff = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9+7; /**********showtime************/ const int maxm = 2e7+9; const int maxn = 1e6+9; int le[maxn],ri[maxn]; int lto[maxn],rto[maxn]; ll f[maxm]; int g(int x) { return x + 10000000; } int main(){ int n; scanf("%d", &n); for(int i=1; i<=n; i++) scanf("%d%d", &le[i], &ri[i]); int sum = 0; /// 向右扩展 le[n+1] = 1000000000; for(int i=1; i<=n; i++) { sum += ri[i] - le[i] + 1; rto[i] = min(sum, le[i+1] - ri[i] - 1); sum -= le[i+1] - ri[i] - 1; if(sum < 0) sum = 0; } /// 向左扩展 sum = 0; ri[0] = -1; for(int i=n; i>=1; i--) { sum += ri[i] - le[i] + 1; lto[i] = min(sum , le[i] - ri[i-1] -1); sum -= le[i] - ri[i-1] - 1; if(sum < 0) sum = 0; } ///计算每个点的前缀和。lowsum保存前缀和比当前点小的个数 ll ans = 0, lowsum = 0; int s = 0, pos = 0; f[g(0)] = 1; for(int i=1; i<=n; i++) { for(int j=max(pos, le[i] - lto[i]); j<=ri[i] + rto[i]; j++) { if(j>=le[i] && j <= ri[i]) { lowsum += f[g(s)]; s++; f[g(s)]++; ans += lowsum; } else { s--; lowsum -= f[g(s)]; f[g(s)]++; ans += lowsum; } // cout<<j<<" "<<lowsum<<endl; pos = j+1; } } // cout<<endl; printf("%lld\n", ans); return 0; }
skr