The Preliminary Contest for ICPC Asia Shenyang 2019
B Dudu's maze
题目链接
题意:n个点,m条边构成一张图,每个点都是一个房间,房间里可能有糖果和怪兽,再给出人的初始位置(保证初始位置为糖果屋)。人具有一点魔法值,当其走到糖果屋时,可以拿走糖果,当其走到怪兽屋,可以用魔法值转移到相邻房间,或者退出迷宫,求退出迷宫时,拿到糖果的期望。
思路:并查集所有联通糖果屋,搜索联通块再计算期望。
#include <bits/stdc++.h> #define maxn 100005 using namespace std; int n,m,k; int fa[maxn]; int sz[maxn]; int u[maxn<<1],v[maxn<<1]; int vis[maxn];; int book[maxn]; vector <int>G[maxn]; vector <int>vt; void init(int n){ for(int i=1;i<=n;i++){ fa[i]=i; vis[i]=0; sz[i]=1; G[i].clear(); book[i]=0; } vt.clear(); } int find(int x){ return x==fa[x]?x:fa[x]=find(fa[x]); } void mix(int x,int y){ int fx=find(x); int fy=find(y); if(fx!=fy){ fa[fx]=fy; sz[fy]+=sz[fx]; sz[fx]=0; } } void bfs(int x){ queue <int>q; book[x]=1; q.push(x); while(!q.empty()){ int f=q.front(); q.pop(); for(int i=0;i<G[f].size();i++){ if(book[G[f][i]]){ continue; } if(!vis[G[f][i]]){ q.push(G[f][i]); book[G[f][i]] = 1; }else vt.push_back(G[f][i]); } } } void input(){ scanf("%d%d%d",&n,&m,&k); int i,x; init(n); for(i=0;i<m;i++){ scanf("%d%d",&u[i],&v[i]); G[u[i]].push_back(v[i]); G[v[i]].push_back(u[i]); } for(i=1;i<=k;i++) { scanf("%d",&x); vis[x]=1; sz[x] = 0; } for(i=0;i<m;i++){ if(!vis[find(u[i])]&&!vis[find(v[i])]){ mix(u[i],v[i]); } } } void solve(){ double store = sz[find(1)]; sz[find(1)] = 0; bfs(1); int siz = vt.size(); long long temp; double ans = 0, esum; for(int i = 0;i < siz;i++){ esum = G[vt[i]].size(); temp = 0; for(int j = 0;j < esum;j++){ temp += sz[find(G[vt[i]][j])]; //cout << find(G[vt[i]][j]) << " " << sz[find(G[vt[i]][j])] << endl; } //cout << temp << " " << esum << endl; if(temp * 1.0 / esum> ans){ ans = temp * 1.0 / esum; } } printf("%.8lf\n",ans + store); } int main(){ int t; scanf("%d",&t); while(t--){ input(); solve(); } } /*4 4 2 1 2 2 3 3 4 4 1 2 3*/
C Dawn-K's water
题目链接
完全背包+枚举
#include<bits/stdc++.h> using namespace std; using ll = long long; const ll inf = 0x3f3f3f3f3f3f3f3f; ll p[1003], c[1004]; ll dp[20004]; int main() { ll n, m; while (~scanf("%lld%lld", &n, &m)) { //n = 1000; m = 1e4; ll ma = 0; for (ll i = 1; i <= n; i++) { scanf("%lld%lld", &p[i], &c[i]); ma = max(c[i], ma); // p[i] = 1e9;c[i] = 1; } memset(dp, inf, sizeof dp); ll M = max(ma * 2, m * 2); dp[0] = 0; for (ll i = 1; i <= n; i++) { for (ll j = c[i]; j <= M; j++) { if (dp[j] > dp[j - c[i]] + p[i]) { dp[j] = dp[j - c[i]] + p[i]; } } } ll ans1 = inf, ans2 = -1; for (ll i = m; i <= M; i++) { if (ans1 > dp[i]) { ans1 = dp[i]; ans2 = i; } else if (ans1 == dp[i]) { ans2 = i; } } printf("%lld %lld\n", ans1, ans2); } } /* 3 3 2 1 3 1 1 1 3 5 1 2 2 3 3 3 */
D Fish eating fruit
题目链接
题意:n个点构成一颗树,求两点之间边权%3余0、余1、余2的边权值总和
思路:正解,树形dp。也可用点分治做。对于分治得到每个树,记录当前的余0、余1、余2的边权个数,通过个数可以得到组合后的各个权值总和。点分治、容斥子树得到最后答案。
#include <bits/stdc++.h> #define maxn 100005 #define inf 0x3f3f3f3f typedef long long ll; using namespace std; const int mod=1000000007; struct edge{ int to;ll cost;int next; }; edge G[maxn<<1]; int head[maxn]; int edgeNum; int mx,rt; int Size; int sz[maxn]; int book[maxn]; ll sum[3]; ll ans[3]; ll fin[3]; int n,u,v,w; void add_edge(int a,int b,int c){ G[edgeNum].to=b; G[edgeNum].cost=c; G[edgeNum].next=head[a]; head[a]=edgeNum++; } void dfsroot(int u,int fa){ sz[u]=1; int num=0; for(int i=head[u];i!=-1;i=G[i].next){ int v=G[i].to; if(book[v]||v==fa) continue; dfsroot(v,u); sz[u]+=sz[v]; num=max(num,sz[v]); } num=max(num,Size-sz[u]); if(num<mx){ mx=num; rt=u; } } void query(int u,int fa,ll val){ sum[val%3]++; ans[val%3]+=val; for(int i=head[u];i!=-1;i=G[i].next){ int v=G[i].to; if(v==fa||book[v]) continue; query(v,u,(val+G[i].cost)); } } void solve(int u,ll val,int flag){ // cout<<"U"<<u<<' '<<flag<<endl; sum[0]=sum[1]=sum[2]=0; ans[0]=ans[1]=ans[2]=0; query(u,-1,val); // cout<<"!!!"<<sum[0]<<' '<<sum[1]<<' '<<sum[2]<<endl; // cout<<"???"<<ans[0]<<' '<<ans[1]<<' '<<ans[2]<<endl; ll temp1,temp2,temp3; temp1=temp2=temp3=0; temp1+=ans[0]*(sum[0]-1)+sum[2]*ans[1]+sum[1]*ans[2]; temp2+=ans[2]*(sum[2]-1)+sum[1]*ans[0]+sum[0]*ans[1]; temp3+=ans[1]*(sum[1]-1)+sum[2]*ans[0]+sum[0]*ans[2]; // cout<<temp1<<' '<<temp2<<' '<<temp3<<endl; if(flag){ fin[0]+=ans[0]+temp1; fin[1]+=ans[1]+temp2; fin[2]+=ans[2]+temp3; fin[0]=fin[0]%mod; fin[1]=fin[1]%mod; fin[2]=fin[2]%mod; }else { fin[0]-=ans[0]+temp1; fin[1]-=ans[1]+temp2; fin[2]-=ans[2]+temp3; fin[0]=(fin[0]+mod)%mod; fin[1]=(fin[1]+mod)%mod; fin[2]=(fin[2]+mod)%mod; } // cout<<fin[0]<<' '<<fin[1]<<' '<<fin[2]<<endl; } void devide(int u){ solve(u,0,1); book[u]=1; int tot=Size; for(int i=head[u];i!=-1;i=G[i].next) { int v=G[i].to; if(book[v]) continue; solve(v,G[i].cost,0); rt=0; Size=sz[v]>sz[u]?tot-sz[u]:sz[v]; mx=inf; dfsroot(v,-1); devide(rt); } } void input(){ for(int i=1;i<n;i++){ scanf("%d%d%d",&u,&v,&w); u++;v++; add_edge(u,v,w); add_edge(v,u,w); } } void solve(){ Size=n; mx=inf; dfsroot(1,0); devide(rt); } int main(){ while(scanf("%d",&n)!=EOF){ memset(head,-1,sizeof head); memset(fin,0,sizeof fin); memset(book,0,sizeof book); memset(sz,0,sizeof sz); edgeNum=0; input(); solve(); printf("%lld %lld %lld\n",fin[0]*2%mod,fin[1]*2%mod,fin[2]*2%mod); } }
F Honk's pool
题目链接
题意:每次挑出最大的,令其减一,然后挑出最小的,令其加一。共操作 K 次,求最大值和最小值的差。
思路:二分
#include<iostream> #include<cstdio> #include<cstring> #include<map> #include<vector> #include<set> #include<queue> #include<algorithm> #include<string> #include<cmath> #include<stack> #include<functional> #include<bitset> #define ll long long #define maxn 1000002 const int INF = 0x3f3f3f3f; using namespace std; int num[maxn * 5]; ll pre[maxn * 5]; int main(void){ ll n, k, i, add, sub, l, r, m, pos; ll sum; num[0] = -1; pre[0] = 0; while(scanf("%lld %lld",&n,&k)!=EOF){ for(i = 1;i <= n;i++){ scanf("%lld",&num[i]); } num[n + 1] = 1e9 + 7; sort(num + 1,num + n + 1); for(i = 1;i <= n;i++){ pre[i] = pre[i - 1] + num[i]; } sum = pre[n]; l = 0; r = 1e9 + 1; while(l <= r){ m = (l + r) >> 1; pos = lower_bound(num,num + n + 1,m) - num - 1; if(sum - pre[pos] - (n - pos) * m > k){ l = m + 1; } else{ r = m - 1; } } sub = l; l = 0; r = 1e9 + 1; while(l <= r){ m = (l + r) >> 1; pos = upper_bound(num,num + n + 1,m) - num - 1; if(m * pos - pre[pos] > k){ r = m - 1; } else{ l = m + 1; } } add = r; if(add >= sub){ if(pre[n] % n == 0){ puts("0"); } else{ puts("1"); } } else{ printf("%d\n",sub - add); } } return 0; }
H Texas hold'em Poker
题目链接
题意:打牌顺子、对子。。等若干规则,给出规则排序。
思路:模拟
#include <bits/stdc++.h> #define maxn 100005 using namespace std; int n; struct node{ char name[10]; int p[5]; int level; int sum1=0; int level2=0,sum2=0; int level31=0,level32=0,sum3=0; int level4=0,sum4=0; int level5=0,sum5=0; int level6=0,sum6=0; }nod[maxn]; void calc(char s[],int index,int len){ int cnt=0; for(int i=0;i<len;i++){ if(s[i]>='2'&&s[i]<='9'){ nod[index].p[cnt]=s[i]-'0'; } if(s[i]=='A') nod[index].p[cnt]=1; if(s[i]=='J') nod[index].p[cnt]=11; if(s[i]=='Q') nod[index].p[cnt]=12; if(s[i]=='K') nod[index].p[cnt]=13; if(s[i]=='1') { nod[index].p[cnt]=10; i++; } cnt++; } sort(nod[index].p,nod[index].p+5); } void calclevel(int index){ if(nod[index].p[0]==1&&nod[index].p[1]==10&&nod[index].p[2]==11&&nod[index].p[3]==12&&nod[index].p[4]==13){ nod[index].level=8; return ; } if(nod[index].p[0]==nod[index].p[1]-1&&nod[index].p[1]==nod[index].p[2]-1&&nod[index].p[2]==nod[index].p[3]-1&&nod[index].p[3]==nod[index].p[4]-1) { nod[index].level=7; return; } if((nod[index].p[0]==nod[index].p[1]&&nod[index].p[0]==nod[index].p[2]&&nod[index].p[0]==nod[index].p[3])||(nod[index].p[4]==nod[index].p[1]&&nod[index].p[4]==nod[index].p[2]&&nod[index].p[4]==nod[index].p[3])){ nod[index].level=6; if(nod[index].p[0]==nod[index].p[1]&&nod[index].p[0]==nod[index].p[2]&&nod[index].p[0]==nod[index].p[3]){ nod[index].level6=nod[index].p[0]; nod[index].sum6=nod[index].p[4]; } if(nod[index].p[4]==nod[index].p[1]&&nod[index].p[4]==nod[index].p[2]&&nod[index].p[4]==nod[index].p[3]){ nod[index].level6=nod[index].p[4]; nod[index].sum6=nod[index].p[0]; } return; } if((nod[index].p[0]==nod[index].p[1]&&nod[index].p[0]==nod[index].p[2]&&nod[index].p[3]==nod[index].p[4])||(nod[index].p[2]==nod[index].p[3]&&nod[index].p[2]==nod[index].p[4]&&nod[index].p[0]==nod[index].p[1])){ nod[index].level=5; if(nod[index].p[0]==nod[index].p[1]&&nod[index].p[0]==nod[index].p[2]&&nod[index].p[3]==nod[index].p[4]){ nod[index].level5=nod[index].p[0]; nod[index].sum5=nod[index].p[3]; } if(nod[index].p[2]==nod[index].p[3]&&nod[index].p[2]==nod[index].p[4]&&nod[index].p[0]==nod[index].p[1]){ nod[index].level5=nod[index].p[2]; nod[index].sum5=nod[index].p[0]; } return; } if((nod[index].p[0]==nod[index].p[1]&&nod[index].p[0]==nod[index].p[2])||(nod[index].p[1]==nod[index].p[2]&&nod[index].p[1]==nod[index].p[3])||(nod[index].p[2]==nod[index].p[3]&&nod[index].p[2]==nod[index].p[4])){ nod[index].level=4; if(nod[index].p[0]==nod[index].p[1]&&nod[index].p[0]==nod[index].p[2]){ nod[index].level4=nod[index].p[0]; nod[index].sum4=nod[index].p[3]+nod[index].p[4]; } if(nod[index].p[1]==nod[index].p[2]&&nod[index].p[1]==nod[index].p[3]){ nod[index].level4=nod[index].p[1]; nod[index].sum4=nod[index].p[0]+nod[index].p[4]; } if(nod[index].p[2]==nod[index].p[3]&&nod[index].p[2]==nod[index].p[4]){ nod[index].level4=nod[index].p[2]; nod[index].sum4=nod[index].p[0]+nod[index].p[1]; } return; } if((nod[index].p[0]==nod[index].p[1]&&nod[index].p[2]==nod[index].p[3])||(nod[index].p[0]==nod[index].p[1]&&nod[index].p[3]==nod[index].p[4])||(nod[index].p[1]==nod[index].p[2]&&nod[index].p[3]==nod[index].p[4])){ nod[index].level=3; if(nod[index].p[0]==nod[index].p[1]&&nod[index].p[2]==nod[index].p[3]){ nod[index].level31=nod[index].p[0]; nod[index].level32=nod[index].p[2]; if(nod[index].level31<nod[index].level32) swap(nod[index].level31,nod[index].level32); nod[index].sum3=nod[index].p[4]; } if(nod[index].p[0]==nod[index].p[1]&&nod[index].p[3]==nod[index].p[4]){ nod[index].level31=nod[index].p[0]; nod[index].level32=nod[index].p[3]; if(nod[index].level31<nod[index].level32) swap(nod[index].level31,nod[index].level32); nod[index].sum3=nod[index].p[2]; } if(nod[index].p[1]==nod[index].p[2]&&nod[index].p[3]==nod[index].p[4]){ nod[index].level31=nod[index].p[1]; nod[index].level32=nod[index].p[3]; if(nod[index].level31<nod[index].level32) swap(nod[index].level31,nod[index].level32); nod[index].sum3=nod[index].p[0]; } return; } if((nod[index].p[0]==nod[index].p[1])||(nod[index].p[1]==nod[index].p[2])||(nod[index].p[2]==nod[index].p[3])||(nod[index].p[3]==nod[index].p[4])){ nod[index].level=2; if(nod[index].p[0]==nod[index].p[1]){ nod[index].level2=nod[index].p[0]; nod[index].sum2=nod[index].p[2]+nod[index].p[3]+nod[index].p[4]; } if(nod[index].p[1]==nod[index].p[2]){ nod[index].level2=nod[index].p[1]; nod[index].sum2=nod[index].p[0]+nod[index].p[3]+nod[index].p[4]; } if(nod[index].p[2]==nod[index].p[3]){ nod[index].level2=nod[index].p[2]; nod[index].sum2=nod[index].p[1]+nod[index].p[0]+nod[index].p[4]; } if(nod[index].p[3]==nod[index].p[4]){ nod[index].level2=nod[index].p[3]; nod[index].sum2=nod[index].p[1]+nod[index].p[2]+nod[index].p[0]; } return; } nod[index].level=1; nod[index].sum1=nod[index].p[0]+nod[index].p[1]+nod[index].p[2]+nod[index].p[3]+nod[index].p[4]; return; } bool cmp(node a,node b){ if(a.level==b.level){ if(a.level==1){ if(a.sum1==b.sum1) return strcmp(a.name,b.name)<0; return a.sum1>b.sum1; }else if(a.level==2){ if(a.level2==b.level2){ if(a.sum2==b.sum2) return strcmp(a.name,b.name)<0; return a.sum2>b.sum2; } return a.level2>b.level2; }else if(a.level==3){ if(a.level31==b.level31){ if(a.level32==b.level32){ if(a.sum3==b.sum3) return strcmp(a.name,b.name)<0; return a.sum3>b.sum3; } return a.level32>b.level32; } return a.level31>b.level31; }else if(a.level==4){ if(a.level4==b.level4){ if(a.sum4==b.sum4) return strcmp(a.name,b.name)<0; return a.sum4>b.sum4; } return a.level4>b.level4; }else if(a.level==5){ if(a.level5==b.level5){ if(a.sum5==b.sum5) return strcmp(a.name,b.name)<0; return a.sum5>b.sum5; } return a.level5>b.level5; }else if(a.level==6){ if(a.level6==b.level6){ if(a.sum6==b.sum6) return strcmp(a.name,b.name)<0; return a.sum6>b.sum6; } return a.level6>b.level6; }else if(a.level==7){ if(a.p[4]==b.p[4]) return strcmp(a.name,b.name)<0; return a.p[4]>b.p[4]; }else{ return strcmp(a.name,b.name)<0; } } return a.level>b.level; } void input(){ int i; char s[10]; for(i=1;i<=n;i++){ scanf("%s%s",nod[i].name,s); int len=strlen(s); calc(s,i,len); calclevel(i); // for(int j=0;j<5;j++) // cout<<nod[i].p[j]<<endl; } } void solve(){ sort(nod+1,nod+n+1,cmp); for(int i=1;i<=n;i++){ printf("%s\n",nod[i].name); // cout<<nod[i].level<<endl; } } int main(){ while(scanf("%d",&n)!=EOF){ input(); solve(); } }
K Guanguan's Happy water
题目链接
题意:水过
#include<bits/stdc++.h> using namespace std; using ll = long long; const ll maxn = 1e5 + 5; const ll mod = 1e9 + 7; ll a[maxn]; ll qpow(ll A, ll B) { ll t = 1; while (B) { if ((B & 1)) { t = t * A%mod; } A = A * A%mod; B = B >> 1; } return t; } int main() { //prllf("%lld\n",5LL*qpow()) ll t; scanf("%lld", &t); while (t--) { ll k, n; scanf("%lld%lld", &k, &n); ll K = k * 2; ll sum = 0; ll sm = 0; ll sum2 = 0; for (ll i = 1; i <= K; i++) { scanf("%lld", &a[i]); if (i <= n)sm += a[i]; if (i > k)sum2 += a[i]; sum += a[i]; sum %= mod; sum2 %= mod; sm %= mod; } ll ans = sm % mod; if (n >= K) { ans = (sum2%mod * qpow(k, mod - 2) % mod*((n - K) % mod) % mod + sum % mod) % mod; } printf("%lld\n", ans); } }