Gym 102091 2018-2019 ACM-ICPC, Asia Nakhon Pathom Regional Contest(组队训练)

solved:9/12

upsolved:10/12

A:solved

B:/

C:solved

D:solved

E:upsolved

F:solved

G:solved

H:solved

I:/

J:solved

K:solved

L:solved

A.

题解:

按高度从高到低,每次将区间中最高点给选出来,然后将左右能连边的区间看成虚点,从最高点向虚点连边,再从虚点向该区间中最高点连边;

这样就变成了一个分层的DAG,奇数层虚点(第1层为超级根),偶数层实点;

这个玩意的结构很类似树,所以我们可以用类似搞树的方法搞这个

然后直接统计每个点的深度和每个子DAG的最深深度

然后询问直接用深度搞就行,特别地需要判一下是否属于同一棵子树

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 const int maxn = 100005;
  5 int st[17][maxn], lo[maxn], a[maxn], n, m, base;
  6 vector<int> g[maxn];
  7 
  8 struct node
  9 {
 10     int val, dep, maxdep;
 11 }tr[maxn << 1];
 12 
 13 int find(int l, int r)
 14 {
 15     int t = lo[r - l + 1];
 16     return max(st[t][l], st[t][r - (1 << t) + 1]);
 17 }
 18 
 19 int makedag(int nd, int l, int r, int dep)
 20 {
 21     //printf("? %d %d %d\n", l, r, dep);
 22     tr[nd].dep = dep;
 23     int maxval = find(l, r);
 24     int lpos = lower_bound(g[maxval].begin(), g[maxval].end(), l) - g[maxval].begin();
 25     int rpos = upper_bound(g[maxval].begin(), g[maxval].end(), r) - g[maxval].begin() - 1;
 26     vector<int> tmp; tmp.clear(); tmp.push_back(l - 1);
 27     vector< pair<int, int> > inter; inter.clear();
 28     for(int i = lpos; i <= rpos; ++ i)
 29     {
 30         int p = g[maxval][i];
 31         tmp.push_back(p);
 32         tr[p].dep = dep + 1;
 33         //printf("! %d %d %d\n", dep, p, tr[p].dep);
 34     }
 35     tmp.push_back(r + 1);
 36     for(int i = 1; i <= rpos - lpos + 2; i ++)
 37         if(tmp[i] - 1 > tmp[i - 1])
 38         {
 39             base ++; int t = base;
 40             int v = makedag(base, tmp[i - 1] + 1, tmp[i] - 1, dep + 2);
 41             inter.push_back(make_pair(t, v));
 42         }else inter.push_back(make_pair(0, 0));
 43     int ret = 0;
 44     for(int i = 1; i <= rpos - lpos + 1; i ++)
 45     {
 46         int p = tmp[i];
 47         tr[p].maxdep = max(inter[i - 1].second, inter[i].second);
 48         tr[p].maxdep = max(tr[p].maxdep, tr[p].dep);
 49         ret = max(ret, tr[p].maxdep);
 50     }
 51     return ret;
 52 }
 53 
 54 int abs(int x){return x < 0 ? -x : x;}
 55 
 56 int lg[maxn], rg[maxn];
 57 stack<int> s;
 58 
 59 int main()
 60 {
 61     lo[1] = 0; for(int i = 2; i <= 100000; ++ i) lo[i] = lo[i >> 1] + 1;
 62     scanf("%d%d", &n, &m); a[0] = a[n + 1] = n + 100;
 63     for(int i = 1; i <= n; ++ i)
 64     {
 65         scanf("%d", &a[i]);
 66         g[a[i]].push_back(i);
 67         st[0][i] = a[i];
 68     }
 69     for(int i = 1; i <= n; ++ i) g[i].push_back(0), g[i].push_back(n + 1), sort(g[i].begin(), g[i].end());
 70     for(int k = 1; (1 << k) <= n; ++ k)
 71         for(int i = 1; i + (1 << k) - 1 <= n; ++ i)
 72             st[k][i] = max(st[k - 1][i], st[k - 1][i + (1 << (k - 1))]);
 73     base = n + 1; makedag(base, 1, n, 0);
 74     while(!s.empty()) s.pop(); s.push(0);
 75     for(int i = 1; i <= n; ++ i)
 76     {
 77         while(a[i] > a[s.top()]) s.pop();
 78         lg[i] = s.top() + 1;
 79         s.push(i);
 80     }
 81     while(!s.empty()) s.pop(); s.push(n + 1);
 82     for(int i = n; i >= 1; -- i)
 83     {
 84         while(a[i] > a[s.top()]) s.pop();
 85         rg[i] = s.top() - 1;
 86         s.push(i);
 87     }
 88     while(m --)
 89     {
 90         int x, y; scanf("%d%d", &x, &y);
 91         if(y == 0)printf("%d\n", (tr[x].maxdep - tr[x].dep) >> 1);
 92         else 
 93         {
 94             if(a[x] < a[y]) swap(x, y);
 95             if(a[x] == a[y] || y < lg[x] || y > rg[x]) printf("0\n");
 96             else printf("%d\n", abs(tr[x].dep - tr[y].dep) >> 1);
 97         }
 98     }
 99     return 0;
100 }
View Code

B.

unsolved

C.

签到题

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn = 5005;
 5 
 6 pair<int, int> st[maxn];
 7 int n, m, a[maxn], ans[maxn];
 8 
 9 int main()
10 {
11     scanf("%d%d", &n, &m);
12     for(int i = 1; i <= n; i ++)
13     {
14         scanf("%d", &a[i]);
15         st[i] = make_pair(a[i], i);
16     }
17     sort(st + 1, st + n + 1);
18     int ret = 0;
19     for(int i = 1; i <= n; ++ i) ans[i] = 0;
20     for(int i = 1; i <= n; ++ i)
21     {
22         int pos = st[i].second;
23         int val = -1;
24         for(int j = max(1, pos - m); j <= min(n, pos + m); ++ j)
25             if(a[j] < a[pos]) val = max(val, ans[j]);
26         ans[pos] = val + 1;
27         ret = max(ret, ans[pos]);
28     }
29     printf("%d\n", ret);
30     return 0;
31 }
View Code

D.

签到题

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn = 2000005;
 5 int T, n, a[maxn];
 6 
 7 int abs(int x){return x < 0 ? -x : x;}
 8 
 9 int main()
10 {
11     scanf("%d", &T);
12     while(T --)
13     {
14         scanf("%d", &n);
15         for(int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
16         sort(a + 1, a + n + 1);
17         int cnt = 0, now = 0;
18         for(int i = 1; i <= n; ++ i)
19         {
20             if(now == 0 || abs(now - a[i]) > 10)
21             {
22                 cnt ++;
23                 now = a[i] + 10;
24             }
25         }
26         printf("%d\n", cnt);
27     }
28     return 0;
29 }
View Code

E.

题解:

写法不优就很容易写挂的题目。。。

考虑dp[i][j]表示dp到值为i,用了j次机会的最长长度

然后讨论转移就行了

注意枚举数字时候不要枚举值,枚举每一个数字会更好写

 1 #include<bits/stdc++.h>
 2 #define maxn 305
 3 using namespace std;
 4 int T,n,cas;
 5 int a[maxn];
 6 int dp[maxn][3];
 7 int main()
 8 {
 9     scanf("%d",&T);
10     while(T--)
11     {
12         ++cas;
13         scanf("%d",&n);
14         memset(a,0,sizeof(a));
15         memset(dp,0,sizeof(dp));
16         for(int i=1;i<=n;++i)scanf("%d",&a[i]);
17         sort(a+1,a+n+1);
18         for(int i=1;i<=n;++i)
19         {
20             int t=a[i]+100;
21             for(int j=2;j>=1;--j)
22             {
23                 dp[t+1][j]=max(dp[t+1][j-1],max(dp[t][j-1],dp[t-1][j-1]))+1;
24             }
25             for(int j=2;j>=0;--j)
26             {
27                 dp[t][j]=max(dp[t][j],max(dp[t-1][j],dp[t-2][j]))+1;
28             }
29             for(int j=2;j>=1;--j)
30             {
31                 dp[t-1][j]=max(dp[t-1][j-1],max(dp[t-2][j-1],dp[t-3][j-1]))+1;
32             }
33         }
34         int ans=0;
35         for(int i=1;i<=300;++i)
36             for(int j=0;j<=2;++j)
37             {
38                 ans=max(ans,dp[i][j]);
39             }
40         printf("Case %d: %d\n",cas,ans);
41     }
42 }
View Code

F.

题解:

同UOJ275,利用Lucas定理转化,将C(n,m)中的n,m写成7进制数,存在某一位n的数位比m小

然后按数位计数就行了

 1 #include<cstdio>
 2 #define mo 1000000007
 3 using namespace std;
 4 int T;
 5 long long n;
 6 long long a[70],qr[70],g[70];
 7 int main()
 8 {
 9     scanf("%d",&T);
10     for (int oo=1;oo<=T;++oo)
11     {
12         scanf("%lld",&n);
13         a[0]=0;
14         long long tmp=n;
15         while (tmp)
16             a[++a[0]]=tmp%7,
17             tmp/=7;
18         qr[0]=1;
19         g[0]=1;
20         for (int i=1;i<=a[0]+1;++i)
21             qr[i]=qr[i-1]*7LL%mo,
22             g[i]=1LL*g[i-1]*28%mo;
23         long long ans=0,p=0,q=1;
24         for (int i=a[0];i>=1;--i)
25         {
26             for (int j=0;j<=a[i]-1;++j)
27                 ans=(ans+1LL*((p*7LL+j)%mo*qr[i-1])%mo*qr[i-1]%mo+(qr[i-1]+1LL)*qr[i-1]%mo*((mo+1)/2)%mo-1LL*q*(j+1)%mo*g[i-1]%mo)%mo;
28             p=(p*7LL+a[i])%mo;
29             q=q*(a[i]+1LL)%mo;
30         }
31         long long cnt=1;
32         for (int i=1;i<=a[0];++i) cnt=cnt*(a[i]+1LL)%mo;
33         printf("Case %d: %lld\n",oo,((ans+n+1-cnt)%mo+mo)%mo);
34     }
35 }
View Code

G.

题解:

SCC模板题

 1 #include<bits/stdc++.h>
 2 #define maxn 205
 3 using namespace std;
 4 int T,n,m;
 5 vector<int> g[maxn],scc[maxn];
 6 stack<int> s;
 7 int pre[maxn],low[maxn],belong[maxn];
 8 int t,cnt;
 9 void dfs(int u)
10 {
11     pre[u]=low[u]=++t;
12     s.push(u);
13     for(int i=0;i<g[u].size();++i)
14     {
15         int v=g[u][i];
16         if(!pre[v])dfs(v),low[u]=min(low[u],low[v]);
17         else if(!belong[v])low[u]=min(low[u],pre[v]);
18     }
19     if(low[u]==pre[u])
20     {
21         ++cnt;
22         while(1)
23         {
24             int x=s.top();s.pop();
25             belong[x]=cnt;
26             scc[cnt].push_back(x);
27             if(x==u)break;
28         }
29     }
30 }
31 int main()
32 {
33     scanf("%d",&T);
34     while(T--)
35     {
36         scanf("%d%d",&n,&m);
37         for(int i=1;i<=n;++i)g[i].clear(),scc[i].clear(),pre[i]=low[i]=belong[i]=0;
38         t=cnt=0;
39         while(!s.empty())s.pop();
40         for(int u,v,i=1;i<=m;++i)
41         {
42             scanf("%d%d",&u,&v);
43             u++;v++;
44             g[u].push_back(v);
45         }
46         for(int i=1;i<=n;++i)if(!pre[i])dfs(i);
47         printf("%d\n",cnt);
48     }
49 }
View Code

H.

题解:

观察(榜)发现可能有一些奥妙重重的性质

可以直接枚举0~2^21 check

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 int T;
 5 ll A,B,C,NA,NB,NC;
 6 int main()
 7 {
 8     scanf("%d",&T);
 9     while(T--)
10     {
11         cin>>NA>>NB>>NC>>A>>B>>C;
12         for(int i=0;i<(1<<21);++i)
13         {
14             ll t=1ll*i*i*i;
15             if(t%NA==A&&t%NB==B&&t%NC==C)
16             {
17                 cout<<i<<endl;
18                 break;
19             }
20         }
21     }
22 }
View Code

I.

unsolved

J.

题解:

考虑利用三次方差因式分解提出一个1e-15,然后单独统计前面的部分

这样会被卡常

忽略高阶的1e-15就能过了

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const double eps = 1e-15;
 5 const double mi = 1.0 / 3.0;
 6 double sum = 0;
 7 int x, y;
 8 
 9 void pri(int p)
10 {
11     char s[10];
12     int cc = 0;
13     s[3] = s[2] = s[1] = 48;
14     while(p > 0)
15     {
16         s[++ cc] = 48 + (p % 10);
17         p /= 10;
18     }
19     for(int i = 3; i >= 1; i --) putchar(s[i]);
20     puts("");
21 }
22 
23 int main()
24 {
25     while(scanf("%d%d", &x, &y) == 2 && 1ll * x + 1ll * y > 0)
26     {
27         sum = 0;
28         for(int i = x; i <= y; ++ i)
29         {
30             double p1 = (double)i + eps;
31             double p2 = (double)i;
32             double tmp = 3.0 * pow(p1 * p2, mi);
33             //printf("%d %.5Lf\n", i, (double)1.0 / tmp);
34             sum += (double)1.0 / tmp;
35         }
36         int cnt = 15;
37         while(sum + eps < 1) {cnt ++; sum *= 10.0;}
38         while(sum >= 10 + eps) {cnt --; sum /= 10.0;}
39         printf("%.5lfE-", sum); pri(cnt);
40     }
41     return 0;
42 }
View Code

K.

题解:

动态维护第k小,线段树上二分

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 const int maxn = 100005;
  5 const int maxm = 1000005;
  6 
  7 struct FastIO
  8 {
  9     static const int S=5<<20;
 10     int wpos;char wbuf[S];
 11     FastIO():wpos(0){}
 12     inline int xchar()
 13     {
 14         static char buf[S];
 15         static int len=0,pos=0;
 16         if(pos==len)pos=0,len=fread(buf,1,S,stdin);
 17         if(pos==len)return -1;
 18         return buf[pos++];
 19     }
 20     inline int xuint()
 21     {
 22         int c=xchar(),x=0;
 23         while(~c&&c<=32)c=xchar();
 24         for(;'0'<=c&&c<='9';c=xchar())x=x*10+c-'0';
 25         return x;
 26     }
 27 }io;
 28 
 29 int vsh[maxn], vs[maxn], vc, vsc, lsh[maxn << 1], ls[maxn << 1], lsc, cc, T, n;
 30 struct event
 31 {
 32     int tp, bg, ed, val;
 33     void read()
 34     {
 35         tp = io.xuint();
 36         //scanf("%d", &tp);
 37         bg = io.xuint();
 38         val = io.xuint();
 39         if(tp == 1) ed = io.xuint();
 40         lsh[++ cc] = bg;
 41         if(tp == 1)lsh[++ cc] = ed + 1;
 42         if(tp == 1) vsh[++ vc] = val;
 43     }
 44 }ev[maxn];
 45 vector<int> g[maxn << 1];
 46 struct node
 47 {
 48     int ls, rs, l, r, sum;
 49     void clear(int x, int y){ls = rs = sum = 0; l = x; r = y;}
 50 }tr[maxm << 1];
 51 
 52 void mt(int x, int y)
 53 {
 54     tr[cc].clear(x, y);
 55     if(x == y) return;
 56     int t = cc, mid = (x + y) >> 1;
 57     cc ++; tr[t].ls = cc; mt(x, mid);
 58     cc ++; tr[t].rs = cc; mt(mid + 1, y);
 59 }
 60 
 61 void add(int rt, int pos, int val)
 62 {
 63     if(tr[rt].l == tr[rt].r)
 64     {
 65         tr[rt].sum += val;
 66         return;
 67     }
 68     int mid = (tr[rt].l + tr[rt].r) >> 1;
 69     if(pos <= mid) add(tr[rt].ls, pos, val);
 70     else add(tr[rt].rs, pos, val);
 71     tr[rt].sum = tr[tr[rt].ls].sum + tr[tr[rt].rs].sum;
 72 }
 73 
 74 int query(int rt, int las)
 75 {
 76     //printf("!!! %d %d\n", rt, las);
 77     if(tr[rt].l == tr[rt].r) return tr[rt].l;
 78     int ls = tr[rt].ls, rs = tr[rt].rs;
 79     if(tr[ls].sum >= las) return query(ls, las);
 80     else return query(rs, las - tr[ls].sum);
 81 }
 82 
 83 int main()
 84 {
 85     //freopen("K.in", "r", stdin);
 86     T = io.xuint();
 87     //scanf("%d", &T);
 88     for(int cas = 1;  cas <= T; ++ cas)
 89     {
 90         n = io.xuint();
 91         //scanf("%d", &n); 
 92         cc = 0; vc = 0;
 93         for(int i = 1; i <= (n << 1); ++ i) g[i].clear();
 94         for(int i = 1; i <= n; ++ i) ev[i].read();
 95         sort(lsh + 1, lsh + cc + 1);
 96         sort(vsh + 1, vsh + vc + 1);
 97         ls[lsc = 1] = lsh[1]; vs[vsc = 1] = vsh[1];
 98         for(int i = 2; i <= cc; ++ i) if(lsh[i] != lsh[i - 1]) ls[++ lsc] = lsh[i];
 99         for(int i = 2; i <= vc; ++ i) if(vsh[i] != vsh[i - 1]) vs[++ vsc] = vsh[i];
100         for(int i = 1; i <= n; ++ i)
101             if(ev[i].tp == 1)
102             {
103                 int pos = lower_bound(ls + 1, ls + lsc + 1, ev[i].ed + 1) - ls;
104                 int vp = lower_bound(vs + 1, vs + vsc + 1, ev[i].val) - vs;
105                 g[pos].push_back(vp);
106             }
107         cc = 1; mt(1, vsc);
108         printf("Case %d:\n", cas);
109         int xx = 1;
110         for(int i = 1; i <= n; ++ i)
111         {
112             int now = lower_bound(ls + 1, ls + lsc + 1, ev[i].bg) - ls;
113             while(xx <= now)
114             {
115                 for(int p : g[xx]) add(1, p, -1);
116                 xx ++;
117             }
118             if(ev[i].tp == 1) add(1, lower_bound(vs + 1, vs + vsc + 1, ev[i].val) - vs, 1);
119             if(ev[i].tp == 2)
120             {
121                 if(ev[i].val > tr[1].sum) puts("-1");
122                 else printf("%d\n", vs[query(1, ev[i].val)]);
123             }
124         }
125     }
126     return 0;
127 }
View Code

L.

题解:

二分边长二维前缀和check

卡读入,要fastio

 1 #include<bits/stdc++.h>
 2 #define maxn 1005
 3 using namespace std;
 4 int T;
 5 int n,m;
 6 int a[maxn][maxn],sum[maxn][maxn];
 7 bool check(int x,int y,int r)
 8 {
 9     return sum[x+r-1][y+r-1]-sum[x-1][y+r-1]-sum[x+r-1][y-1]+sum[x-1][y-1]<=1;
10 }
11 int solve(int x,int y)
12 {
13     int l=0,r=min(n-x+1,m-y+1),ans=0;
14     while(l<=r)
15     {
16         int mid=(l+r)>>1;
17         if(check(x,y,mid))ans=mid,l=mid+1;
18         else r=mid-1;
19     }
20     return ans;
21 }
22 struct FastIO
23 {
24     static const int S=5<<20;
25     int wpos;char wbuf[S];
26     FastIO():wpos(0){}
27     inline int xchar()
28     {
29         static char buf[S];
30         static int len=0,pos=0;
31         if(pos==len)pos=0,len=fread(buf,1,S,stdin);
32         if(pos==len)return -1;
33         return buf[pos++];
34     }
35     inline int xuint()
36     {
37         int c=xchar(),x=0;
38         while(~c&&c<=32)c=xchar();
39         for(;'0'<=c&&c<='9';c=xchar())x=x*10+c-'0';
40         return x;
41     }
42 }io;
43 int main()
44 {
45     T=io.xuint();
46     while(T--)
47     {
48         n=io.xuint();m=io.xuint();
49         for(int i=1;i<=n;++i)
50             for(int j=1;j<=m;++j)a[i][j]=io.xuint();
51         for(int i=1;i<=n;++i)
52             for(int j=1;j<=m;++j)sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
53         int ans=0;
54         for(int i=1;i<=n;++i)
55             for(int j=1;j<=m;++j)
56             {
57                 ans=max(ans,solve(i,j));
58             }
59         printf("%d\n",ans);
60     }
61 }
View Code

猜你喜欢

转载自www.cnblogs.com/uuzlove/p/10808636.html