传送门

B. Dudu's maze

题意:

是什么鬼东西???我读题可以读半小时QAQ

给出一张无向图,一个人在里面收集糖果,每个点都有一个糖果,特殊点除外。当他第一次进入特殊点时,会随机往一条边走;之后再进入特殊点时,直接退出。

问最后期望获得的糖果数为多少。

思路:

  • 注意到这个人肯定会贪心走的,即是每次到一个连通块,肯定要把里面的糖果都拿完,然后再选一个随机走。
  • 不管往哪个方向,还是类似地贪心走,将那个连通块走完。
  • 所以就两次\(dfs\)好了,第一次\(dfs\)首先求出第一个连通块,然后标出所有的特殊点;第二次\(dfs\)以特殊点为起点搜连通块。

大体思路就是这样,注意一些细节:就是可能以某个特殊点为起点的时候,会多次到达同一个连通块,但答案不能重复计算。这里我的解决办法就是用了一个类似于时间戳一样的东西来进行标记,同一个连通块的属于同一个时间,并且用一个数组记录时间的答案。

详见代码:

Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100005, M = 200005; int n, m, k;
int T;
bool chk[N]; struct Edge{
int v, next;
}e[M << 1];
int head[N], tot;
void adde(int u, int v) {
e[tot].v = v; e[tot].next = head[u]; head[u] = tot++;
} bool vis[N];
vector <int> vec;
int dfs(int u) {
int sz = 1; vis[u] = 1;
for(int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].v;
if(vis[v] || chk[v]) {
if(chk[v]) vec.push_back(v);
continue;
}
sz += dfs(v);
}
return sz;
} int dfn;
int D[N], ans[N], du[N];
int dfs2(int u) {
int sz = (chk[u] ? 0 : 1);
D[u] = dfn; vis[u] = 1;
for(int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].v;
if(chk[v]) continue;
if(vis[v]) {
if(chk[u] && !chk[v]) sz += ans[D[v]];
continue;
}
if(chk[u]) {
ans[++dfn] = dfs2(v);
sz += ans[dfn];
}
else sz += dfs2(v);
}
return sz;
} int main() {
// freopen("input.in", "r", stdin);
cin >> T;
while(T--) {
cin >> n >> m >> k;
for(int i = 0; i <= n; i++) {
du[i] = ans[i] = D[i] = 0;
head[i] = -1; chk[i] = vis[i] = false;
}
vec.clear();
tot = 0;
for(int i = 1; i <= m; i++) {
int u, v; scanf("%d%d", &u, &v);
adde(u, v); adde(v, u);
++du[u], ++du[v];
}
for(int i = 1; i <= k; i++) {
int x; scanf("%d", &x);
chk[x] = true;
}
int res = dfs(1), tmp;
double ANS = 0;
dfn = 0;
for(auto it : vec) {
int sz = dfs2(it);
ANS = max(ANS, res + 1.0 * sz / du[it]);
}
printf("%.8f\n", ANS);
}
return 0;
}

C. Dawn-K's water

简单\(dp\)。

Code
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
const int MAXN = 1e4+5,MAXM = 2e6+5,MOD = 998244353,INF = 0x3f3f3f3f;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
const db eps = 1e-9;
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define mid l + ((r-l)>>1)
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define pii pair<int,int>
#define vii vector<pii>
#define vi vector<int>
using namespace std; int n,m,p[1005],c[1005];
ll f[10005];
int main(){
ios::sync_with_stdio(false);
//freopen("../A.in","r",stdin);
//freopen("../A.out","w",stdout);
while(cin>>n>>m){
ll ans=1000000000000000;
int b=-1,up=10000,sum=0;
for(int i=1;i<=n;i++){
cin>>p[i]>>c[i];
sum+=c[i];
}
//up=min(up,sum);
f[0]=0;
for(int i=1;i<=up;i++)f[i]=1000000000000000;
for(int i=1;i<=n;i++){
for(int j=c[i];j<=up;j++){
f[j] = min(f[j],f[j-c[i]] + p[i]);
}
}
for(int i=m;i<=up;i++){
if(f[i]<=ans){
ans=f[i];
b=i;
}
}
//assert(ans>=1&&ans<=1000000000);
assert(b!=-1);
cout<<ans<<' '<<b<<'\n';
}
return 0;
}

D. Fish eating fruit

题意:

这什么题意啊,欺负我英语不好么QAQ

思路:

按照模\(3\)余数分类,然后换根\(dp\)就行了。

代码队友写的,可能有点迷(我反正没怎么看懂)

Code
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
const int MAXN = 1e4+5,MAXM = 2e4+5,MOD = 1e9+7,INF = 0x3f3f3f3f;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
const db eps = 1e-9;
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define mid l + ((r-l)>>1)
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define pii pair<int,int>
#define vii vector<pii>
#define vi vector<int>
using namespace std;
struct Edge{
int v,w,next;
}e[MAXM];
int n,a,b,c,head[MAXN],cnt,f1[MAXN][3],g1[MAXN][3],ans[3],f2[MAXN][3],g2[MAXN][3];
inline void init(){
cnt=0;
for(int i=1;i<=n;i++)head[i]=0;
for(int i=1;i<=n;i++){
for(int r=0;r<3;r++)f1[i][r]=g1[i][r]=0;
}
}
inline void addEdge(int u,int v,int w){
e[++cnt] = {v,w,head[u]};head[u]=cnt;
}
inline void add(int &x,int y){
x+=y;
if(x>=MOD)x-=MOD;
}
void dfs(int u,int p){
g1[u][0]=1;
for(int i=head[u];i;i=e[i].next){
int v=e[i].v;
if(v==p)continue;
dfs(v,u);
for(int r=0;r<3;r++){
add(f1[u][(e[i].w+r)%3],(f1[v][r] + (ll)g1[v][r]*e[i].w%MOD)%MOD);
add(g1[u][(e[i].w+r)%3],g1[v][r]);
}
}
}
void solve(int u,int p){
for(int i=head[u];i;i=e[i].next){
int v=e[i].v;
if(v==p)continue;
for(int r=0;r<3;r++){
int t = (r+e[i].w)%3;
int t2 = ((r-e[i].w)%3+3)%3;
add(f2[v][t],(f2[u][r]-f1[v][t2]-(ll)g1[v][t2]*e[i].w + (ll)e[i].w*(g2[u][r] - g1[v][t2])%MOD+MOD)%MOD);
add(g2[v][t],(g2[u][r]-g1[v][t2]+MOD)%MOD);
}
solve(v,u);
}
}
int main(){
ios::sync_with_stdio(false);
//freopen("../A.in","r",stdin);
//freopen("../A.out","w",stdout);
while(cin>>n){
init();
for(int i=1;i<n;i++){
cin>>a>>b>>c;
a++;b++;
addEdge(a,b,c);addEdge(b,a,c);
}
dfs(1,0);
for(int i=1;i<=n;i++){
for(int r=0;r<=2;r++){
g2[i][r] =g1[i][r];
f2[i][r] =f1[i][r];
}
}
solve(1,0);
memset(ans,0,sizeof(ans));
for(int i=1;i<=n;i++){
for(int r=0;r<3;r++)add(ans[r],f2[i][r]);
}
cout<<ans[0]<<' '<<ans[1]<<' '<<ans[2]<<'\n';
}
return 0;
}

F. Honk's pool

考虑先取最大的数,可以二分一个最后的最大值,然后随便搞搞,把取完过后的数组求出来。

之后贪心依次来放就行。

总的来说,就是将取和放独立开,这两个是独立的,并不影响。

为什么?

我也不会证= =。

Code
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll; const int N = 500005; ll k, n;
ll a[N], sum[N]; bool chk(int x) {
int p = lower_bound(a + 1, a + n + 1, x) - a;
int num = n - p + 1;
ll S = sum[p] - 1ll * x * num;
return S <= k;
} int main() {
ios::sync_with_stdio(false); cin.tie(0);
while(cin >> n >> k) {
for(int i = 1; i <= n; i++) cin >> a[i];
sort(a + 1, a + n + 1); sum[n + 1] = 0;
for(int i = n; i >= 1; i--) sum[i] = sum[i + 1] + a[i];
int l = 0, r = INF, mid;
while(l < r) {
mid = (l + r) >> 1;
if(chk(mid)) r = mid;
else l = mid + 1;
}
int v = r;
int p = lower_bound(a + 1, a + n + 1, v) - a;
int num = n - p + 1;
ll S = sum[p] - 1ll * v * num;
k -= S;
for(int i = p; i <= n; i++) a[i] = v;
for(int i = p; i <= min(n, p + k - 1); i++) {
if(a[i]) { --a[i]; ++S; }
}
// for(int i = 1; i <= n; i++) cout << a[i] << ' ';
// cout << '\n';
int cnt = 1, f = 1;
for(int i = 1; i <= n; i++) {
if(a[i] >= v) break;
ll tmp = 1ll * cnt * (a[i + 1] - a[i]);
if(S <= tmp) {
int now = S / cnt;
cout << v - (a[i] + now) << '\n';
f = 0; break;
}
S -= 1ll * cnt * (a[i + 1] - a[i]);
++cnt;
}
if(f == 0) continue;
if(S % n) cout << 1 << '\n';
else cout << 0 << '\n';
}
return 0;
}
/*
3 10000000
1 2 3
*/

H. Texas hold'em Poker

题意:

不懂。

思路:

模拟。

Code
#include<cstdio>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
#define REP(r,x,y) for(register int r=(x); r<y; r++)
#ifdef sahdsg
#define DBG(...) printf(__VA_ARGS__)
#else
#define DBG(...) (void)0
#endif
template <class T>
inline void read(T&x) {
static int si=1; static char ch; x=0;
do ch=getchar(); while(!isdigit(ch) && ch!='-');
if(ch=='-') si=-1, ch=getchar();
while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} x*=si;
}
template <class T, class... A> inline void read(T&t, A&...a){read(t); read(a...);}
#define MAXN 100007
char nm[MAXN][17];
struct node {
int id;
int s[5];
int kind;
int v,v2,v3;
};
node p[MAXN];
inline void readpai(int x) {
char ch;
REP(i,0,5) {
do ch=getchar(); while(ch<=' ');
#define L p[x].s[i]
switch(ch) {
case 'A':
L=1; break;
case '1':
getchar();
L=10; break;
case 'J':
L=11; break;
case 'Q':
L=12; break;
case 'K':
L=13; break;
default:
L=ch-'0'; break;
}
#undef L
}
sort(p[x].s,p[x].s+5);
}
inline void processpai(int x) {
const int *X=p[x].s; int &K=p[x].kind, &V=p[x].v, &V2=p[x].v2, &V3=p[x].v3;
//7 XJQKA
const int RS[]={1,10,11,12,13};
if(memcmp(X,RS,sizeof RS)==0) {K=7;V=0;return;}
//6 12345
if(X[1]-X[0]==1 && X[2]-X[1]==1 && X[3]-X[2]==1 && X[4]-X[3]==1) {K=6, V=X[4]; return;}
//5 AAAA
if(X[1]==X[2] && X[2]==X[3]) {
if(X[0]==X[1]) {K=5, V=X[1], V2=X[4]; return;}
if(X[3]==X[4]) {K=5, V=X[1], V2=X[0]; return;}
}
//4 AAABB
if(X[0]==X[1] && X[1]==X[2] && X[3]==X[4]) {K=4, V=X[0], V2=X[3]; return;}
if(X[0]==X[1] && X[2]==X[3] && X[3]==X[4]) {K=4, V=X[2], V2=X[0]; return;}
//3 AAABC
if(X[0]==X[1] && X[1]==X[2]) {K=3, V=X[0], V2=X[3]+X[4]; return;}
if(X[1]==X[2] && X[2]==X[3]) {K=3, V=X[1], V2=X[0]+X[4]; return;}
if(X[2]==X[3] && X[3]==X[4]) {K=3, V=X[2], V2=X[0]+X[1]; return;}
//2 AABBC
if(X[0]==X[1] && X[2]==X[3]) {K=2, V=X[2], V2=X[0], V3=X[4]; return;}
if(X[0]==X[1] && X[3]==X[4]) {K=2, V=X[3], V2=X[0], V3=X[2]; return;}
if(X[1]==X[2] && X[3]==X[4]) {K=2, V=X[3], V2=X[1], V3=X[0]; return;}
//1 AABCD
if(X[0]==X[1]) {K=1, V=X[0], V2=X[2]+X[3]+X[4]; return;}
if(X[1]==X[2]) {K=1, V=X[1], V2=X[0]+X[3]+X[4]; return;}
if(X[2]==X[3]) {K=1, V=X[2], V2=X[0]+X[1]+X[4]; return;}
if(X[3]==X[4]) {K=1, V=X[3], V2=X[0]+X[1]+X[2]; return;}
//0
{K=0, V=X[0]+X[1]+X[2]+X[3]+X[4];return;}
}
bool nmcmp(const node&l, const node&r) {
return strcmp(nm[l.id],nm[r.id])<0;
}
bool cmp(const node&l, const node&r) {
const bool T=false;
if(l.kind<r.kind) return T;
if(l.kind==r.kind) {
switch(l.kind) {
case 0:
case 6:
case 7:
if(l.v<r.v) return T;
if(l.v==r.v) return nmcmp(l,r);
else return !T;
case 1:
case 3:
case 4:
case 5:
if(l.v<r.v) return T;
if(l.v==r.v) {
if(l.v2<r.v2) return T;
if(l.v2==r.v2) {
return nmcmp(l,r);
} else return !T;
} else return !T;
case 2:
if(l.v<r.v) return T;
if(l.v==r.v) {
if(l.v2<r.v2) return T;
if(l.v2==r.v2) {
if(l.v3<r.v3) return T;
if(l.v3==r.v3) {
return nmcmp(l,r);
} else return !T;
} else return !T;
} else return !T;
}
}
return !T; }
int main() {
int n;
while(~scanf("%d", &n)) {
REP(i,0,n) {
scanf("%s", nm[i]);
p[i].id=i;
readpai(i);
processpai(i);
}
sort(p,p+n,cmp);
REP(i,0,n) {
puts(nm[p[i].id]);
}
}
return 0;
}

J. Ghh Matin

题意:

给出\(n\)个点,现在随机生成边,要求每个点只有一条出边和一条入边(形成若干个环)。同时给出一个\(x\)。

问最后生成的最长环不超过\(x\)的概率。

注意\(2x\geq n\)。

思路:

首先可以知道,对于\(n\)个点,随机形成若干个环的情况总数为\(n!\)。为什么?

因为最后的图中肯定有\(n\)条边,我们现在开始一条一条加边,第一次选择两个出度为\(0\)和入度为\(0\)的点将其相连,易知一开始有\(n\)总选择,后面依次有\(n-1,n-2,\cdots,1\)种选择。

注意条件\(2x\geq n\),那么说明图中长度大于\(x\)的环最多只有一个,那么我们考虑反面,就枚举所有不合法的情况,此时就很好计算:

假设现在考虑长度为\(m\)的环,那么首先会从\(n\)个里面选择\(m\)个,之后会随机成环,此时只有\((m-1)!\)种情况,相当于固定一个点,其它点随机排列(如果直接全排列,可能会有重复的)。之后剩下的点随机成环,有\((n-m)!\)种情况。

那么反面情况的总概率为:

\[\sum_{m=x+1}^n{n\choose m}(m-1)!(n-m)!/n!
\]

之后随便化一化就出来了。

正难则反。

Code
#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
//#define Local
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e6 + 5, MOD = 1e9 + 7; int n, x;
int p[N]; ll qpow(ll a, ll b) {
ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return ans;
} void init() {
for(int i = 1; i < N; i++) p[i] = qpow(i, MOD - 2);
} void run() {
cin >> n >> x;
int ans = 0;
for(int i = x + 1; i <= n; i++) ans = (ans + p[i]) % MOD;
ans = (1 - ans + MOD) % MOD;
cout << ans << '\n';
} int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
#ifdef Local
freopen("../input.in", "r", stdin);
freopen("../output.out", "w", stdout);
#endif
init();
int T; cin >> T;
while(T--) run();
return 0;
}

The Preliminary Contest for ICPC Asia Shenyang 2019的更多相关文章

  1. The Preliminary Contest for ICPC Asia Shenyang 2019 F. Honk's pool

    题目链接:https://nanti.jisuanke.com/t/41406 思路:如果k的天数足够大,那么所有水池一定会趋于两种情况: ① 所有水池都是一样的水位,即平均水位 ② 最高水位的水池和 ...

  2. The Preliminary Contest for ICPC Asia Shenyang 2019 H. Texas hold'em Poker

    题目链接:https://nanti.jisuanke.com/t/41408 题目意思很简单,就是个模拟过程. #include <iostream> #include <cstr ...

  3. The Preliminary Contest for ICPC Asia Shenyang 2019 C. Dawn-K's water

    题目:https://nanti.jisuanke.com/t/41401思路:完全背包 #include<bits/stdc++.h> using namespace std; int ...

  4. The Preliminary Contest for ICPC Asia Shenyang 2019 H

    H. Texas hold'em Poker 思路:根据每个牌型分等级,然后排序按照等级优先,最大值次之,次大值,最后比较剩下值的和. #include<bits/stdc++.h> us ...

  5. The Preliminary Contest for ICPC Asia Shenyang 2019 C Dawn-K's water (完全背包)

    完全背包为什么要取到M,可以取到2*M嘛,这题需要整取,对于不能整取的背包容量,dp[k]=INF,以及dp[j-water[i].weight]=INF时,dp[j]也不需要更新.如果不整取的话,后 ...

  6. The Preliminary Contest for ICPC Asia Shenyang 2019 D. Fish eating fruit(树形dp)

    题意:求一棵树上所有路径和模3分别为0 1 2 的权值的和 思路:树形dp 增加一个记录儿子节点满足条件的个数的数组 不要放在一起dp不然答案跟新会有问题 #include <bits/stdc ...

  7. The Preliminary Contest for ICPC Asia Shanghai 2019 C Triple(FFT+暴力)

    The Preliminary Contest for ICPC Asia Shanghai 2019 C Triple(FFT+暴力) 传送门:https://nanti.jisuanke.com/ ...

  8. The Preliminary Contest for ICPC Asia Nanjing 2019/2019南京网络赛——题解

    (施工中……已更新DF) 比赛传送门:https://www.jisuanke.com/contest/3004 D. Robots(期望dp) 题意 给一个DAG,保证入度为$0$的点只有$1$,出 ...

  9. 计蒜客 41391.query-二维偏序+树状数组(预处理出来满足情况的gcd) (The Preliminary Contest for ICPC Asia Xuzhou 2019 I.) 2019年徐州网络赛)

    query Given a permutation pp of length nn, you are asked to answer mm queries, each query can be rep ...

随机推荐

  1. Linux使用alias自定义命令自定义快捷键

    比如我经常需要进入一个很深的目录如 /home/walking/weblogic/devlop/script/application/.../... 这样每次进入这个目录操作是不是很麻烦,可能有时候记 ...

  2. puppeteer开发

    Chromium下载问题 https://github.com/GoogleChrome/puppeteer/ https://download-chromium.appspot.com/?platf ...

  3. 计算几何 val.3

    目录 计算几何 val.3 自适应辛普森法 定积分 引入 辛普森公式 处理精度 代码实现 模板 时间复杂度 练习 闵可夫斯基和 Pick定理 结论 例题 后记 计算几何 val.3 自适应辛普森法 可 ...

  4. hive操作简单总结

    Hive DDL.DML操作 背景介绍 • 一.DDL操作(数据定义语言)包括:Create.Alter.Show.Drop等. • create database- 创建新数据库 • alter d ...

  5. web.xml的常见配置

    web.xml的常见配置 <!-- 配置全局的编码过滤器 --> <filter> <description>编码过滤器</description> & ...

  6. XSS劫持cookie登录

    <script>alert (document.cookie)</script>  获取cookie 实验环境用的DVWA 先用系统账号登录,admin    password ...

  7. zipalign的使用

    zipalign 是一个存档对齐工具,可为Android应用程序(.apk)文件提供重要的优化.目的是确保所有未压缩数据以相对于文件开头的特定对齐开始.具体来说,它会导致.apk中的所有未压缩数据(如 ...

  8. Flutter 快速上手定时器/倒计时及实战讲解

    本文微信公众号「AndroidTraveler」首发. 今天给大家讲讲 Flutter 里面定时器/倒计时的实现. 一般有两种场景: 我只需要你在指定时间结束后回调告诉我.回调只需要一次. 我需要你在 ...

  9. Fiddler常用设置

    1.设置抓取HTTPS请求 勾选后弹窗添加证书确认框 点击yes后,弹出警告 点击是,成功添加证书 点击OK确认,设置成功了 成功抓取到HTTPS请求 2.自定义会话框,展示GET和POST请求 3. ...

  10. @supports特性查询

    特性查询也就是@supports规则,这个属性是作为CSS2.0扩展被引入的,是检测浏览器是否支持css属性值,是由逻辑与,逻辑或和逻辑非组合而成.主要的目的就是为了作者能够在不同的浏览器上根据不同的 ...