含【最小球覆盖】【最大流isap】模板。
题面pdf
G---Pyramid【数论】【规律】【递推式】
题意:
度为$n$的Pyramid是一个由$frac{n(n+1)}{2}$个三角形组成大三角形。比如度为3的Pyramid是下面这样子。
现在由这些顶点组成等边三角形,问有多少个。
思路:
zyn先放到坐标系里打了个表,然后发现差的差是一个等差数列....
于是就可以有递推关系式了。矩阵快速幂T了
所以只能解方程,把系数解出来。
注意取模求逆元!
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const ll mod=1e9+7; 5 ll n; 6 ll fpow(ll a,ll n) 7 { 8 ll res=1,base=a%mod; 9 while(n) 10 { 11 if(n&1) res*=base, res%=mod; 12 base*=base, base%=mod; 13 n>>=1; 14 } 15 return res%mod; 16 } 17 ll inv(ll a){return fpow(a,mod-2);} 18 int main() 19 { 20 int T; 21 cin>>T; 22 while(T--) 23 { 24 scanf("%I64d",&n); 25 ll ans=0; 26 ans+=fpow(n,4), ans%=mod; 27 ans+=6*fpow(n,3)%mod, ans%=mod; 28 ans+=11*fpow(n,2)%mod, ans%=mod; 29 ans+=6*n%mod, ans%=mod; 30 ans*=inv(24), ans%=mod; 31 printf("%I64d ",ans); 32 } 33 }
I---Magic Potion【网络流】
题意:
有$n$个英雄,$m$只怪物。每个英雄可以杀某些指定的怪物,但是他们只能杀一次。现在有$k$瓶药水,喝了一瓶药水就可以多杀一只怪物,但是每个英雄最多只能喝一瓶。问他们最多可以杀多少怪物。
思路:
想dp想了半天想不出来。丢给zyn他直接就说是网络流。噢好有道理。
每个英雄和怪物之间有一条权值为1的边,源点和英雄有一个权值为1的边,怪物和汇点有权值唯一的边。
这样跑出来的最大流是不考虑喝药水的情况的答案。
现在可以喝药水了,相当于多了一个节点,源点到这个节点的边权值是k,然后这个节点和每个英雄有权值是1的边。
相当于给$k$个英雄多了一条1的流量,又限制了每个英雄只能喝一瓶。
听说Dinic T了,所以后来自己直接套的isap的板子。【其实还并不很熟网络流】
1 #include<iostream> 2 //#include<bits/stdc++.h> 3 #include<cstdio> 4 #include<cmath> 5 #include<cstdlib> 6 #include<cstring> 7 #include<algorithm> 8 #include<queue> 9 #include<vector> 10 #include<set> 11 #include<climits> 12 #include<map> 13 using namespace std; 14 typedef long long LL; 15 #define N 100010 16 #define pi 3.1415926535 17 #define inf 0x3f3f3f3f 18 19 const int maxn = 505; 20 int n, m, k; 21 struct edge{ 22 int v, w, nxt; 23 }e[maxn* maxn + 5 * maxn]; 24 int h[maxn * 2], tot; 25 int gap[maxn * 2], last[maxn * 2], d[maxn * 2], que[maxn * 2], ql, qr; 26 27 void addedge(int u, int v, int w) 28 { 29 e[++tot] = (edge){v, w, h[u]}; 30 h[u] = tot; 31 e[++tot] = (edge){u, 0, h[v]}; 32 h[v] = tot; 33 } 34 35 36 void init(int s, int t) 37 { 38 memset(gap, 0, sizeof(gap)); 39 memset(d, 0, sizeof(d)); 40 ++gap[d[t] = 1]; 41 for(int i = 1; i <= n + m + 3; i++){ 42 last[i] = h[i]; 43 } 44 que[ql = qr = 1] = t; 45 while(ql <= qr){ 46 int x = que[ql++]; 47 for(int i = h[x], v = e[i].v; i; i = e[i].nxt, v = e[i].v){ 48 if(!d[v]){ 49 ++gap[d[v] = d[x] + 1], que[++qr] = v; 50 } 51 } 52 } 53 } 54 55 int aug(int x, int s, int t, int mi) 56 { 57 if(x == t)return mi; 58 int flow = 0; 59 for(int &i = last[x], v = e[i].v; i; i = e[i].nxt, v = e[i].v){ 60 if(d[x] == d[v] + 1){ 61 int tmp = aug(v, s, t, min(mi, e[i].w)); 62 flow += tmp, mi -= tmp, e[i].w -= tmp, e[i ^ 1].w += tmp; 63 if(!mi)return flow; 64 } 65 } 66 if(!(--gap[d[x]]))d[s] = n + m + 4; 67 ++gap[++d[x]], last[x] = h[x]; 68 return flow; 69 } 70 71 int maxflow(int s, int t) 72 { 73 init(s, t); 74 int ret = aug(s, s, t, inf); 75 while(d[s] <= n + m + 3)ret += aug(s, s, t, inf); 76 return ret; 77 } 78 79 /*void addedge(int u,int v,int w) { 80 e[++tot]=(edge){v,w,h[u]}; 81 h[u]=tot; 82 e[++tot]=(edge){u,0,h[v]}; 83 h[v]=tot; 84 } 85 void init(int s,int t) { 86 memset(gap,0,sizeof gap),memset(d,0,sizeof d),++gap[d[t]=1]; 87 for (int i=1;i<=n + m + 3;++i) last[i]=h[i]; 88 que[ql=qr=1]=t; 89 while (ql<=qr) { 90 int x=que[ql++]; 91 for (int i=h[x],v=e[i].v;i;i=e[i].nxt,v=e[i].v) if (!d[v]) ++gap[d[v]=d[x]+1],que[++qr]=v; 92 } 93 } 94 int aug(int x,int s,int t,int mi) { 95 if (x==t) return mi; 96 int flow=0; 97 for (int &i=last[x],v=e[i].v;i;i=e[i].nxt,v=e[i].v) if (d[x]==d[v]+1) { 98 int tmp=aug(v,s,t,min(mi,e[i].w)); 99 flow+=tmp,mi-=tmp,e[i].w-=tmp,e[i^1].w+=tmp; 100 if (!mi) return flow; 101 } 102 if (!(--gap[d[x]])) d[s]=n + m + 4; 103 ++gap[++d[x]],last[x]=h[x]; 104 return flow; 105 } 106 int maxflow(int s,int t) { 107 init(s,t); 108 int ret=aug(s,s,t,inf); 109 while (d[s]<=n + m + 3) ret+=aug(s,s,t,inf); 110 return ret; 111 }*/ 112 113 int main() 114 { 115 while(scanf("%d%d%d", &n, &m, &k) != EOF){ 116 //init(1, n+ m + 3); 117 tot = 1; 118 memset(h, 0, sizeof(h)); 119 int s = 1, t = n + m + 3; 120 addedge(s, 2, k); 121 for(int i = 1; i <= n; i++){ 122 addedge(s, 2 + i, 1); 123 addedge(2, 2 + i, 1); 124 int t; 125 scanf("%d", &t); 126 for(int j = 0, mon; j < t; j++){ 127 scanf("%d", &mon); 128 addedge(2 + i, 2 + n + mon, 1); 129 } 130 } 131 for(int i = 1; i <= m; i++){ 132 addedge(2 + n + i, t, 1); 133 } 134 printf("%d ", maxflow(s, t)); 135 } 136 137 return 0; 138 }
D---Country Meow【最小球覆盖】
题意:
三维空间中有$n$个点,现在要在空间中找一个点,使得他到这$n$个点最远的距离最小。
思路:
就是一个最小球覆盖的板子题。找的模拟退火的板子cf过不了了。
用的三分的板子直接就过了。
#include<iostream> //#include<bits/stdc++.h> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<queue> #include<vector> #include<set> #include<climits> #include<map> using namespace std; typedef long long LL; #define N 100010 #define pi 3.1415926535 #define inf 0x3f3f3f3f const int maxn = 105; const double eps = 1e-7; typedef struct {double p[3];}point; point a[maxn]; int n; double cal(point now) { double ans=0.0; for(int i=0;i<n;i++) ans=max(ans,sqrt((a[i].p[0]-now.p[0])*(a[i].p[0]-now.p[0])+(a[i].p[1]-now.p[1])*(a[i].p[1]-now.p[1])+(a[i].p[2]-now.p[2])*(a[i].p[2]-now.p[2]))); return ans; } point del(point now,int cnt) { if(cnt>=3) return now; double r=100000,l=-100000; double dr,dl; point tp1,tp2,ans1,ans2,ans; tp1=tp2=ans=now; while(r-l>eps) { dr=(2*r+l)/3; dl=(2*l+r)/3; tp1.p[cnt]=dl; tp2.p[cnt]=dr; ans1=del(tp1,cnt+1); ans2=del(tp2,cnt+1); if(cal(ans1)>cal(ans2)) { l=dl; ans=ans1; } else { r=dr; ans=ans2; } } return ans; } int main() { // freopen("t.txt","r",stdin); //ios::sync_with_stdio(false); //double ans; while(~scanf("%d", &n)) { for(int i=0; i<n; i++) //cin>>node[i].x>>node[i].y>>node[i].z; scanf("%lf%lf%lf",&a[i].p[0],&a[i].p[1],&a[i].p[2]); //minball(n); //cout<<ans<<endl; point ans; printf("%.7f ",cal(del(ans, 0))); } return 0; }
K---Kangaroo Puzzle
题意:
思路:
这题代码可不能折叠啊。队友太强了!
1 #include<stdio.h> 2 #include<string.h> 3 #include <bits/stdc++.h> 4 5 using namespace std; 6 const int MAX_N = 10; 7 char c[4] = {'L', 'R', 'U', 'D'}; 8 9 int main() 10 { 11 int N, M; 12 cin >> N >> M; 13 string s; 14 for (int i = 1; i <= N; i++) 15 cin >> s; 16 int cnt = 0; 17 srand(56346275); 18 while (cnt++ < 50000) { 19 printf("%c", c[rand()%4]); 20 } 21 puts(""); 22 return 0; 23 }
M---Mediocre String Problem【manacher】【exKMP】
题意:
有一个串$S$,一个串$T$。现在要在$S$中选一段$S[i,j]$,和$T$中的$T[1,k]$拼起来是一串回文。问有多少种不同的三元组$(i,j,k)$
思路:
详细题解见:https://www.cnblogs.com/wyboooo/p/9982651.html
1 #include<iostream> 2 //#include<bits/stdc++.h> 3 #include<cstdio> 4 #include<cmath> 5 //#include<cstdlib> 6 #include<cstring> 7 #include<algorithm> 8 //#include<queue> 9 #include<vector> 10 //#include<set> 11 //#include<climits> 12 //#include<map> 13 using namespace std; 14 typedef long long LL; 15 #define N 100010 16 #define pi 3.1415926535 17 #define inf 0x3f3f3f3f 18 19 const int maxn = 1e6 + 5; 20 char s[maxn], ss[maxn * 2], t[maxn], s_rev[maxn]; 21 LL pre[maxn * 2]; 22 int lens, lent, p[maxn * 2]; 23 24 int init() 25 { 26 ss[0] = '$'; 27 ss[1] = '#'; 28 int lenss = 2; 29 for(int i = 0; i < lens; i++){ 30 ss[lenss++] = s[i]; 31 ss[lenss++] = '#'; 32 } 33 ss[lenss] = '