传送门

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. ES、kibana安装及交互操作

    一.ES的安装与启动 1.ES安装(Windows环境) 下载地址:https://www.elastic.co/cn/downloads/past-releases#elasticsearch 版本 ...

  2. 数据安全管理:RSA加密算法,签名验签流程详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.RSA算法简介 1.加密解密 RSA加密是一种非对称加密,在公开密钥加密和电子商业中RSA被广泛使用.可以在不直接传递密钥的情况下,完成加 ...

  3. pycharm安装第三方包问题解决

    pycharm安装第三方包问题解决 pycharm是一个基于python的非常好用的集成开发环境,而python有许多非常不错的开源第三方库,这就需要将一些这样的第三方库导入到我们的项目中去了.然而, ...

  4. C#中类的实例化过程

    创建某个类型的第一个实例时,所进行的操作顺序为:1.静态变量设置为02.执行静态变量初始化器3.执行基类的静态构造函数4.执行静态构造函数5.实例变量设置为06.执行衯变量初始化器7.执行基类中合适的 ...

  5. jquery 常用选择器基础语法学习

    siblings方法的常用应用场景:选中高亮 实现代码 <!DOCTYPE html> <html> <head> <meta charset="U ...

  6. How to: Calculate a Property Value Based on Values from a Detail Collection 如何:基于详细信息集合中的值计算属性值

    This topic describes how to implement a business class, so that one of its properties is calculated ...

  7. English:Day-to-day 1015

    device session stroll pants & trousers gist deep depth diameter D radius R merge ..

  8. Android View的background和padding

    版权声明:本文为xing_star原创文章,转载请注明出处! 本文同步自http://javaexception.com/archives/181 最近在做一个需求,是对im聊天消息设置气泡背景,之前 ...

  9. MYSQL之事务篇

    目录 事务概述 事务隔离级别 Read Uncommitted Read Committed Repeatable Read Serializable 事务概述 在引入事务之前我们先考虑银行转账的操作 ...

  10. SQLSERVER预读逻辑读物理读

    预读:用估计信息,去硬盘读取数据到缓存.预读100次,也就是估计将要从硬盘中读取了100页数据到缓存. 物理读:查询计划生成好以后,如果缓存缺少所需要的数据,让缓存再次去读硬盘.物理读10页,从硬盘中 ...