博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
XVIII Open Cup named after E.V. Pankratiev. Ukrainian Grand Prix
阅读量:5245 次
发布时间:2019-06-14

本文共 13064 字,大约阅读时间需要 43 分钟。

A. Accommodation Plan

对于已知的$K$个点,离它们距离都不超过$L$的点在树上是一个连通块,考虑在每种方案对应的离$1$最近的点统计。

即对于每个点$x$,统计离它距离不超过$L$的点数$call[x]$,再减去离它和它父亲距离都不超过$L$的点数$cext[x]$,然后用组合数计算方案数。

对于$call[x]$可以通过点分治+排序双指针$O(n\log^2n)$统计。

对于$cext[x]$,注意到$cext[x]=call[x]-csub[x]$,其中$csub[x]$表示$x$点子树中深度在$(dep[x]+L-dis(x,fa[x]),dep[x]+L]$的点数,二维数点问题,扫描线+树状数组维护即可$O(n\log n)$统计。

时间复杂度$O(n\log^2n)$。

#include
#include
using namespace std;typedef long long ll;const int N=100010,P=1000000007;int n,K,L,i,j,x,y,z,fac[N],inv[N],ans;int g[N],nxt[N<<1],v[N<<1],w[N<<1],ok[N<<1],ed,son[N],f[N],all,now;int call[N],csub[N],cnt,bit[N],st[N],en[N],dfn;struct E{ll x;int y;E(){}E(ll _x,int _y){x=_x,y=_y;}}e[N],q[N<<1];inline bool cmp(const E&a,const E&b){return a.x
f[x])f[x]=son[v[i]]; } if(all-son[x]>f[x])f[x]=all-son[x]; if(f[x]
L)j--; call[e[i].y]+=p*j; }}void solve(int x){ int i; cnt=0; dfs(x,0,0); cal(1); for(i=g[x];i;i=nxt[i])if(ok[i]){ cnt=0; dfs(v[i],x,w[i]); cal(-1); } for(i=g[x];i;i=nxt[i])if(ok[i]){ ok[i^1]=0; f[0]=all=son[v[i]]; findroot(v[i],now=0); solve(now); }}void dfs2(int x,int y,ll z){ st[x]=++dfn; e[x]=E(z,x); q[++cnt]=E(z+L,x); for(int i=g[x];i;i=nxt[i])if(v[i]!=y){ q[++cnt]=E(z+L,-v[i]); dfs2(v[i],x,z+w[i]); } en[x]=dfn;}inline void ins(int x){for(;x<=n;x+=x&-x)bit[x]++;}inline int ask(int x){int t=0;for(;x;x-=x&-x)t+=bit[x];return t;}inline int C(int n,int m){return n
0)csub[x]+=y;else csub[x]-=y; } for(fac[0]=i=1;i<=n;i++)fac[i]=1LL*fac[i-1]*i%P; for(inv[0]=inv[1]=1,i=2;i<=n;i++)inv[i]=1LL*(P-inv[P%i])*(P/i)%P; for(i=2;i<=n;i++)inv[i]=1LL*inv[i-1]*inv[i]%P; for(i=1;i<=n;i++)ans=((ans+C(call[i],K))%P+P-C(call[i]-csub[i],K))%P; ans=1LL*ans*fac[K]%P; printf("%d",ans);}

  

B. Card Game

枚举$n$的所有约数判断。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;void fre() { }#define MS(x, y) memset(x, y, sizeof(x))#define ls o<<1#define rs o<<1|1typedef long long LL;typedef unsigned long long UL;typedef unsigned int UI;template
inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }template
inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }const int N = 1e5 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;template
inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }int casenum, casei;int n, m;int a[N];map
mop;int main(){ while(~ scanf("%d%d", &n, &m)){ mop.clear(); int A = 0, B = 0; for(int i = 1; i <= m; i ++){ scanf("%d", &a[i]); gmax(A, a[i]); mop[a[i]] ++; gmax(B, mop[a[i]]); } //printf("%d %d\n", A, B); int ans = 0; for(int i = 1; i * i <= n; i ++){ if(n % i == 0){ int j = n / i; if(i >= A && j >= B){ ans ++; //printf("i j %d %d\n", i, j); } if(i != j && i >= B && j >= A){ ans ++; //printf("j i %d %d\n", j, i); } } } if(ans != 1) puts("NO"); else puts("YES"); } return 0;}/*【trick&&吐槽】【题意】【分析】【时间复杂度&&优化】*/

  

C. The Most Expensive Gift

若循环节长度为$1$,则答案下界为$\frac{n^2}{9}$,经过分析可得循环节长度超过$8$都是不优的。

暴力搜索所有长度不超过$8$的串作为循环节,然后贪心匹配计算长度即可。

时间复杂度$O(3^8n)$。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;void fre() { }#define MS(x, y) memset(x, y, sizeof(x))#define ls o<<1#define rs o<<1|1typedef long long LL;typedef unsigned long long UL;typedef unsigned int UI;template
inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }template
inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }const int N = 10010, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;template
inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }int casenum, casei;int n;char s[N];char a[N];int ans;int len;int check(){ int pos = 0; int now = 0; for(int i = 0; i < n; ++i) { if(s[i] == a[pos]) { ++now; pos = pos + 1; if(pos == len)pos = 0; } } int LEN = now / len * len; return LEN * LEN / len;}int main(){ while(~scanf("%d%s",&n, s)) { ans = 0; for(len = 1; ; ++len) { int bst = n * n / len; if(bst <= ans)break; int top = 1; for(int i = 0; i < len; ++i) { a[i] = 'a'; top *= 3; } for(int tim = 1; tim <= top; ++tim) { gmax(ans, check()); ++a[len - 1]; int pos = len - 1; while(a[pos] == 'd') { a[pos] = 'a'; ++a[--pos]; } } } printf("%d\n", ans); } return 0;}/*【trick&&吐槽】【题意】【分析】【时间复杂度&&优化】*/

  

D. Cut the Cake

两个维度独立,对于一维问题,将所有位置排序,每隔$k$个切一刀即可。

#include
const int N=300;int n,m,k,i,j,dx,dy,cntx,cnty,cx[N],cy[N],qx[N],qy[N];char a[N][N];inline int cal(int xl,int xr,int yl,int yr){ int t=0; for(int i=xl;i<=xr;i++)for(int j=yl;j<=yr;j++)if(a[i][j]=='1')t++; return t;}int main(){ scanf("%d%d%d",&n,&m,&k); for(i=1;i<=n;i++)scanf("%s",a[i]+1); for(i=1;i<=n;i++)for(j=1;j<=m;j++)if(a[i][j]=='1'){ dx++; if(dx%k==0&&dx

  

E. Message

留坑。

 

F. Bad Word

若整个串不是回文串,则答案显然为$1$。

若整个串形如$aaaaa$、$aabaa$、$ababa$,则无解。

否则答案必然是$2$。

#include
const int N=200010;int n,i;char a[N];int main(){ scanf("%d%s",&n,a+1); for(i=1;i<=n;i++)if(a[i]!=a[n-i+1])break; if(i<=n)return puts("1"),0; for(i=1;i<=n;i++)if(a[i]!=a[1])break; if(i>n)return puts("-1"),0; if(n%2==0)return puts("2"),0; for(i=1;i<=n/2;i++)if(a[i]!=a[1])break; if(i>n/2)return puts("-1"),0; for(i=1;i<=n;i++){ if(i>2&&a[i]!=a[i-2])break; } if(i>n)return puts("-1"),0; puts("2");}

  

G. Zenyk, Marichka and Interesting Game

首先将所有石子数都模$A+B$,并剔除小于$\min(A,B)$的堆。

若$A=B$,则根据奇偶性判断即可。

若$A>B$,枚举$A$的第一步行动,然后交换先后手,转化为$A<B$的问题。

若$A<B$:

  • 若$n=0$,则先手必败。
  • 若一步之内可以造出只能$A$拿的堆,即存在石子数$<B$或者$\geq 2A$的堆,那么$A$可以利用这一堆来控制先后手,从而必胜。
  • 否则任何一堆两人都只能恰好拿一次,故根据$n$的奇偶性判断即可。
#include
#include
#include
using namespace std;typedef pair
P;const int N=100010;int n,m,A,B,x,a[N];set

T;int work(int A,int B){ if(T.size()==0)return 0; set

::iterator x=T.begin(); if(x->first

first>=A*2)return 1; return T.size()%2;}int solve(){ int i,ans=0; if(A==B){ for(i=1;i<=m;i++)ans=(ans+a[i]/A)%2; return ans; } if(A
=A){ T.erase(P(a[i],i)); int t=a[i]-A; if(t

  

H. Frog Jumping

贪心用代价最小的若干个青蛙去贪心地走路线。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;void fre() { }#define MS(x, y) memset(x, y, sizeof(x))#define ls o<<1#define rs o<<1|1typedef long long LL;typedef unsigned long long UL;typedef unsigned int UI;template
inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }template
inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }const int N = 1e5 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;template
inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }int casenum, casei;int n, m, K, D;int c[N];LL sum[N];int a[N];int main(){ while(~scanf("%d%d%d%d",&n, &m, &K, &D)) { for(int i = 1; i <= m; ++i)scanf("%d", &c[i]); sort(c + 1, c + m + 1); for(int i = 1; i <= m; ++i) { sum[i] = sum[i - 1] + c[i]; } set
sot; for(int i = 1; i <= K; ++i) { scanf("%d", &a[i]); sot.insert(a[i]); } sort(a + 1, a + K + 1); int way = 0; int pos = 1; sot.insert(n); while(!sot.empty()) { auto it = sot.upper_bound(pos + D); //can't reach it if(it == sot.begin()) { break; } --it; pos = *it; // //printf("pos = %d\n", pos); // if(pos == n) { ++way; if(way >= m)break; pos = 1; } else sot.erase(it); } // //printf("Here: way = %d\n", way); // LL ans = 0; if(way == 0) { a[0] = 1; a[K + 1] = n; for(int i = 1; i <= K + 1; ++i) { int dis = a[i] - a[i - 1]; if(dis > D) { ans += c[1]; } } ans += sum[m] - sum[1]; } else { ans = sum[m - way]; } printf("%lld\n", ans); } return 0;}/*【trick&&吐槽】10 2 3 34 74 8 710 2 2 34 79 5【题意】【分析】【时间复杂度&&优化】*/

  

I. Slot Machine

按照最坏情况模拟即可。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;void fre() { }#define MS(x, y) memset(x, y, sizeof(x))#define ls o<<1#define rs o<<1|1typedef long long LL;typedef unsigned long long UL;typedef unsigned int UI;template
inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }template
inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }const int N = 1e5 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;template
inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }int casenum, casei;int n;vector
vt[N];int a[N];set< pair
>sot[N];int main(){ while(~scanf("%d",&n)) { int ANS = inf; for(int i = 0; i < N; ++i)sot[i].clear(); for(int i = 1; i <= n; ++i) { vt[i].clear(); int g; scanf("%d", &g); for(int j = 1; j <= g; ++j) { int x; scanf("%d", &x); vt[i].push_back(x); } sort(vt[i].begin(), vt[i].end()); int col = 0; for(int j = 0; j < g; ++j) { if(j == g - 1 || vt[i][j] != vt[i][j + 1]) { ++col; } } int cnt = 0; for(int j = 0; j < g; ++j) { ++cnt; if(j == g - 1 || vt[i][j] != vt[i][j + 1]) { if(cnt > 1)gmin(ANS, col + 1); sot[ vt[i][j] ].insert( {col, i} ); cnt = 0; } } } for(int i = 1; i <= n; ++i) { int g = vt[i].size(); int cnt = 0; int col = 0; for(int j = 0; j < g; ++j) { ++cnt; if(j == g - 1 || vt[i][j] != vt[i][j + 1]) { a[++col] = inf; for(auto it : sot[ vt[i][j] ]) { int bl = it.second; if(bl == i && cnt == 1)continue; a[col] = it.first + 1; break; } cnt = 0; } } sort(a + 1, a + col + 1); reverse(a + 1, a + col + 1); for(int j = 1; j <= col; ++j) { //printf("(%d %d): %d\n", i, j, a[j]); gmin(ANS, a[j] + j - 1); } } printf("%d\n", ANS); } return 0;}/*【trick&&吐槽】74 1 2 3 41 11 21 31 47 4 7 4 4 7 7 41 555 1 2 5 3 45 1 2 5 6 75 1 2 5 8 95 1 2 5 10 1120 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 2025 1 2 3 4 51 115 1 2 3 1 2【题意】【分析】【时间复杂度&&优化】*/

  

J. Half is Good

注意到边权在$[0,2^{62})$内随机,故最后$8$位影响排序结果的概率非常小,可以忽略。

还剩$54$位,分成最高的$22$位和后面$32$位,将最高的$22$位相同的边分组,每组内部排序,每组数量都不多。

然后直接求最小生成树即可。

#include
#include
using namespace std;typedef unsigned int U;typedef unsigned long long ll;const int N=10000010,M=(1<<22)+5;int n,m,i,u,v,f[N],have,goal;int g[M],nxt[N],q[1000000];U e[N][3],ans[N/32+10];U s;ll w;inline bool cmp(int x,int y){return e[x][2]
<< 13;s ^= s >> 17;s ^= s << 5;return s;}int F(int x){return f[x]==x?x:f[x]=F(f[x]);}inline void merge(int x){ int a=e[x][0],b=e[x][1]; //printf("merge %d %d\n",a,b); if(F(a)!=F(b)){ have++; ans[x>>5]|=1U<<(x&31); f[f[a]]=f[b]; }}inline void solve(int x){ if(g[x]<0)return; if(nxt[g[x]]<0){ merge(g[x]); return; } int cnt=0; for(int i=g[x];~i;i=nxt[i])q[cnt++]=i; sort(q,q+cnt,cmp); for(int i=0;i
>2; w=w*getnxt(); w>>=8; e[i][0]=u; e[i][1]=v; e[i][2]=w&mask; w>>=32; nxt[i]=g[w]; g[w]=i; //printf("%d %d %llu\n",u,v,w); } for(i=0;i

  

K. Dance

留坑。

 

L. Impress Her

对于一个$A\times B$的包围矩形,因为四连通,至少消耗$A+B$个点,故直接枚举每个矩形内部所有点的时间复杂度为$O(n^3)$。

对于每个点记录其所属矩形,对于每个矩形$x$,枚举内部所有点,检查$x$是否包含该点所属矩形即可,用时间戳来$O(1)$判重。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;void fre() { }#define MS(x, y) memset(x, y, sizeof(x))#define ls o<<1#define rs o<<1|1typedef long long LL;typedef unsigned long long UL;typedef unsigned int UI;template
inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }template
inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }const int N = 505, M = 1e6 + 10, Z = 1e9 + 7, inf = 0x3f3f3f3f;template
inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }int casenum, casei;int n, m;int a[N][N];bool vis[M];bool vs[N][N];int dfn[M];int ymin[M];int ymax[M];int xmin[M];int xmax[M];const int dy[4] = {-1,0,0,1};const int dx[4] = {0,-1,1,0};void dfs(int y, int x){ if(vs[y][x])return; vs[y][x] = 1; gmin(ymin[a[y][x]], y); gmax(ymax[a[y][x]], y); gmin(xmin[a[y][x]], x); gmax(xmax[a[y][x]], x); for(int k = 0; k < 4; ++k) { int yy = y + dy[k]; int xx = x + dx[k]; if(a[yy][xx] == a[y][x]) { dfs(yy, xx); } }}int main(){ while(~scanf("%d%d",&n, &m)) { for(int i = 1; i <= n; ++i) { for(int j = 1; j <= m; ++j) { scanf("%d", &a[i][j]); } } MS(vis, 0); MS(vs,0); MS(ymin, 63); MS(ymax, 0); MS(xmin, 63); MS(xmax, 0); for(int i = 1; i <= n; ++i) { for(int j = 1; j <= m; ++j) { if(!vis[ a[i][j] ]) { vis[ a[i][j] ] = 1; dfs(i, j); } } } MS(dfn, 0); int tim = 0; int ans = 0; for(int i = 1; i <= n; ++i) { for(int j = 1; j <= m; ++j) { int col = a[i][j]; if(vis[col]) { vis[col] = 0; ++tim; for(int y = ymin[col]; y <= ymax[col]; ++y) { for(int x = xmin[col]; x <= xmax[col]; ++x) { int c = a[y][x]; if(c != col && dfn[c] != tim && ymin[c] >= ymin[col] && ymax[c] <= ymax[col] && xmin[c] >= xmin[col] && xmax[c] <= xmax[col] ) { dfn[c] = tim; ++ans; } } } } } } printf("%d\n", ans); } return 0;}/*【trick&&吐槽】【题意】【分析】【时间复杂度&&优化】*/

  

转载于:https://www.cnblogs.com/clrs97/p/8547281.html

你可能感兴趣的文章
centos下同时启动多个tomcat
查看>>
slab分配器
查看>>
分析 PHP大马-php_mof SHELL
查看>>
TCP/IP
查看>>
[推荐] 协同滤波 —— Collaborative Filtering (CF)
查看>>
python中使用中文
查看>>
习题4.14
查看>>
linux 增加用户 useradd 用法小结及配置文件说明
查看>>
Java将Excel中科学计数法解析成数字
查看>>
使用YUM安装MySQL 5.5(适用于CentOS6.2/5.8及Fedora 17/16平台)
查看>>
用jsp写的网页 怎么在传递参数时包含中文?
查看>>
记WinCE下调试SIM900 GSM module
查看>>
[bzoj2819] Nim
查看>>
[bzoj2665] [cqoi2012]编号
查看>>
【java】转义字符
查看>>
NoFragment重大bug
查看>>
洛谷2575高手过招
查看>>
数据清洗
查看>>
linux下几个压缩命令
查看>>
matlab里.*和*的区别
查看>>