2019 The Preliminary Contest for ICPC China Nanchang National Invitational
传送门:
Problem A
温暖的签到题,打个表就行了。
吐槽一下:出题人并没有说用什么格式输出,害得我输出一行怒得一pe
#include <bits/stdc++.h>
using namespace std;
int main()
{cout<<6<<endl;cout<<28<<endl;cout<<496<<endl;cout<<8128<<endl;cout<<33550336<<endl;return 0;
}
Problem B
Problem C
Problem D
Problem E
Problem F
Problem G
Problem H
规律题,经过推倒发现答案为:3n−2∗43^{n-2}*43n−2∗4。
快速幂搞搞就万事了。
#include <iostream>
#include <cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll powm(ll x,ll n){ll res=1;while (n){if (n&1) res=res*x%mod;n>>=1;x=x*x%mod;}return res;
}
int main(){ios::sync_with_stdio(false);cin.tie(0);ll n,ans=0;cin>>n;if (n==1) ans=1;else ans=powm(3,n-2)*4%mod;cout<<ans<<endl;return 0;
}
Problem I
题意:
给你一个长度为nnn的序列,让你找到一个区间[l,r][l,r][l,r],使得∑i=lrai×mini=lrai\sum_{i=l}^{r}{a_i}\times\min_{i=l}^{r}{a_i}i=l∑rai×i=lminrai最大
其中,−106≤ai≤106-10^6\le a_i\le10^6−106≤ai≤106
分析:
如果aia_iai不能取负数,则是poj2796\text{poj2796}poj2796的原题,我们用单调栈对每一个aia_iai处理出以aia_iai为最小值,最左/最右能扩展到的位置,之后直接贪心扫即可。
而在这个题中,因为涉及负数×负数的情况,则我们不能直接累加某段区间的和。
我们考虑用线段树去记录区间前缀和的最大值以及最小值。我们可以贪心的去思考,倘若当前的aia_iai大于000,则显然是取区间[i,ar][i,a_r][i,ar]中的最大值maxmaxmax,以及区间[al,i][a_l,i][al,i]中的最小值minminmin,max−minmax-minmax−min即为以aia_iai为最小值的最大区间和。同理,对于ai<0a_i<0ai<0的情况,我们只需尽量取区间[al,ar][a_l,a_r][al,ar]中的最小区间和即可。
#include <bits/stdc++.h>
using namespace std;
const int maxn=500005;
int a[maxn];
long long sum[maxn];
int n,m;
struct node
{int l,r;long long mx,add,mn;
}tr[maxn*4];
void push_up(int k){tr[k].mx=max(tr[k<<1].mx,tr[k<<1|1].mx);tr[k].mn=min(tr[k<<1].mn,tr[k<<1|1].mn);
}
void build(int k,int l,int r)
{tr[k].l=l,tr[k].r=r;tr[k].add=0;if(l==r){tr[k].mx=sum[l];tr[k].mn=sum[l];return;}int mid=(l+r)>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);push_up(k);
}
void pushdown(int k)
{if(tr[k].add!=0){tr[k<<1].add+=tr[k].add;tr[k<<1].mx+=tr[k].add;tr[k<<1].mn+=tr[k].add;tr[k<<1|1].add+=tr[k].add;tr[k<<1|1].mx+=tr[k].add;tr[k<<1|1].mn+=tr[k].add;tr[k].add=0;}
}
void update(int k,int s,int t,int v)
{int l=tr[k].l,r=tr[k].r;if(l>t||r<s) return;if(l>=s&&r<=t){tr[k].mx+=v;tr[k].mn+=v;tr[k].add+=v;return;}pushdown(k);update(k<<1,s,t,v);update(k<<1|1,s,t,v);push_up(k);
}
long long query(int k,int s,int t)
{int l=tr[k].l,r=tr[k].r;if(l>t||r<s) return 0;if(l>=s&&r<=t) return tr[k].mx;pushdown(k);return max(query(k<<1,s,t),query(k<<1|1,s,t));
}
long long query1(int k,int s,int t)
{int l=tr[k].l,r=tr[k].r;if(l>t||r<s) return 0;if(l>=s&&r<=t) return tr[k].mn;pushdown(k);return min(query1(k<<1,s,t),query1(k<<1|1,s,t));
}
void read(int &ret){ret=0;char ch=getchar();int flag=1;while(ch>'9'||ch<'0'){if(ch=='-')flag=-1;ch=getchar();}while(ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();}ret*=flag;
}
int L[maxn],R[maxn];
long long ans1[maxn],ans2[maxn];
int main()
{//freopen("in.txt","r",stdin);read(n);//cin>>n;for(int i=1;i<=n;i++){read(a[i]);//cin>>a[i];sum[i]=sum[i-1]+a[i];L[i]=R[i]=i;}a[0]=a[n+1]=-0x3f3f3f3f;for(int i=1;i<=n;i++){while(a[i]<=a[L[i]-1])L[i]=L[L[i]-1];}for(int i=n;i>=1;i--){while(a[i]<=a[R[i]+1])R[i]=R[R[i]+1];}int r=1;a[0]=a[n+1]=0;build(1,1,n);for(int i=1;i<=n;i++){update(1,i,n,-a[i-1]);if(a[i]>=0)ans1[i]=query(1,i,R[i]);else ans1[i]=query1(1,i,R[i]);}for(int i=n;i;i--){sum[i]=sum[i+1]+a[i];}build(1,1,n);for(int i=n;i;i--){update(1,1,i,-a[i+1]);if(a[i]>=0)ans2[i]=query(1,L[i],i);else ans2[i]=query1(1,L[i],i);}long long mx=-0x3f3f3f3f3f3f3f3f;for(int i=1;i<=n;i++){mx=max(mx,(ans1[i]+ans2[i]-a[i])*a[i]);}printf("%lld\n",mx);return 0;
}
Problem J
题意:
给你一棵有nnn个节点的树,每条边上有个边权www,现在有qqq个询问,问你在节点uuu到节点vvv的路径中,有多少条边的边权是大于kkk的。
分析:
考虑去二分答案。如果用二分去解的话,这个问题就转化为让你找到一个最小的ttt,使得ttt条边的权值都大于kkk。则显然我们只需要求这段路径上的第ttt大的路径的值,并判断第ttt大的路径的值是否大于kkk即可。
因此我们要求的就是一个经典的树上路径第kkk大的问题,因此我们可以用主席树去解决。
总体的时间复杂度为:O(nlog2(n))\mathcal{O}(nlog^2(n))O(nlog2(n))
代码:
#include <bits/stdc++.h>
using namespace std;const int MAXN = 200010;
const int M = MAXN * 40;
int n,q,m,TOT;
int a[MAXN], t[MAXN];
int T[M], lson[M], rson[M], c[M];void Init_hash()
{for(int i = 1; i <= n;i++)t[i] = a[i];sort(t+1,t+1+n);m = unique(t+1,t+n+1)-t-1;
}
int build(int l,int r)
{int root = TOT++;c[root] = 0;if(l != r){int mid = (l+r)>>1;lson[root] = build(l,mid);rson[root] = build(mid+1,r);}return root;
}
int Hash(int x)
{return lower_bound(t+1,t+1+m,x) - t;
}
int update(int root,int pos,int val)
{int newroot = TOT++, tmp = newroot;c[newroot] = c[root] + val;int l = 1, r = m;while( l < r){int mid = (l+r)>>1;if(pos <= mid){lson[newroot] = TOT++; rson[newroot] = rson[root];newroot = lson[newroot]; root = lson[root];r = mid;}else{rson[newroot] = TOT++; lson[newroot] = lson[root];newroot = rson[newroot]; root = rson[root];l = mid+1;}c[newroot] = c[root] + val;}return tmp;
}
int query(int left_root,int right_root,int LCA,int k)
{int lca_root = T[LCA];int pos = Hash(a[LCA]);int l = 1, r = m;while(l < r){int mid = (l+r)>>1;int tmp = c[lson[left_root]] + c[lson[right_root]] - 2*c[lson[lca_root]] + (pos >= l && pos <= mid);if(tmp >= k){left_root = lson[left_root];right_root = lson[right_root];lca_root = lson[lca_root];r = mid;}else{k -= tmp;left_root = rson[left_root];right_root = rson[right_root];lca_root = rson[lca_root];l = mid + 1;}}return l;
}int rmq[2*MAXN];
struct ST
{int mm[2*MAXN];int dp[2*MAXN][20];void init(int n){mm[0] = -1;for(int i = 1;i <= n;i++){mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];dp[i][0] = i;}for(int j = 1; j <= mm[n];j++)for(int i = 1; i + (1<<j) - 1 <= n; i++)dp[i][j] = rmq[dp[i][j-1]] < rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];}int query(int a,int b){if(a > b)swap(a,b);int k = mm[b-a+1];return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k];}
};
struct Edge
{int to,next,val;
};
Edge edge[MAXN*2];
int tot,head[MAXN];int F[MAXN*2];
int P[MAXN];
int cnt;ST st;
void init()
{tot = 0;memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int val)
{edge[tot].to = v;edge[tot].next = head[u];edge[tot].val=val;head[u] = tot++;
}
void dfs(int u,int pre,int dep)
{F[++cnt] = u;rmq[cnt] = dep;P[u] = cnt;for(int i = head[u];i != -1;i = edge[i].next){int v = edge[i].to;if(v == pre)continue;dfs(v,u,dep+1);F[++cnt] = u;rmq[cnt] = dep;}
}
void LCA_init(int root,int node_num)
{cnt = 0;dfs(root,root,0);st.init(2*node_num-1);
}
int query_lca(int u,int v)
{return F[st.query(P[u],P[v])];
}void dfs_build(int u,int pre)
{int pos = Hash(a[u]);T[u] = update(T[pre],pos,1);for(int i = head[u]; i != -1;i = edge[i].next){int v = edge[i].to;if(v == pre)continue;dfs_build(v,u);}
}
bool check(int u,int v,int k,int val){if(t[query(T[u],T[v],query_lca(u,v),k)]>val) return 1;return 0;
}
int Find(int u,int v,int l,int r,int k){int ret;while(l<=r){int mid=(l+r)>>1;if(check(u,v,mid,k)){ret=mid;r=mid-1;}else l=mid+1;}if(a[query_lca(u,v)]<=k) ret-=1;return ret;
}
void dfs(int u,int fa){for(int i=head[u];~i;i=edge[i].next){int to=edge[i].to;if(to==fa) continue;a[to]=edge[i].val;dfs(to,u);}
}
int main()
{//freopen("in.txt","r",stdin);while(scanf("%d%d",&n,&q) == 2){TOT = 0;int u,v,vv;a[1]=0x3f3f3f3f;init();for(int i = 1;i < n;i++){scanf("%d%d%d",&u,&v,&vv);addedge(u,v,vv);addedge(v,u,vv);}dfs(1,-1);Init_hash();LCA_init(1,n);T[n+1] = build(1,m);dfs_build(1,n+1);int k;while(q--){scanf("%d%d%d",&u,&v,&k);printf("%d\n",Find(u,v,1,n,k)-1);}return 0;}return 0;
}
Problem K
找规律+前缀亦或和
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn=1e5+7;
unsigned int a[maxn],b[maxn][4];
namespace fastIO {#define BUF_SIZE 100000//fread -> readbool IOerror = 0;inline char nc() {static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;if(p1 == pend) {p1 = buf;pend = buf + fread(buf, 1, BUF_SIZE, stdin);if(pend == p1) {IOerror = 1;return -1;}}return *p1++;}inline bool blank(char ch) {return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';}inline void read(int &x) {char ch;while(blank(ch = nc()));if(IOerror) return;for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');}inline void read(unsigned int &x) {char ch;while(blank(ch = nc()));if(IOerror) return;for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');}
#undef BUF_SIZE
};
using namespace fastIO;
int main(){int t;read(t);while (t--){int n,q,l,r;read(n);for (int i=0;i<n;i++) {read(a[i]);b[i][0]=b[i][1]=b[i][2]=b[i][3]=0;}int m=(n+3)/4+1;for (int i=0;i<n;i++)b[i/4+1][i%4]=a[i];
// for (int i=0;i<4;i++){// for (int j=0;j<=m+1;j++) cout<<b[j][i]<<' ';cout<<endl;
// }for (int i=1;i<=m+1;i++) {for (int j=0;j<4;j++)b[i][j]^=b[i-1][j];}read(q);while (q--){read(l);read(r);unsigned ans=0;int tmp=(r-l)%4;l--;r--;if (tmp==3) ans=0;else if (tmp==2) {int ll=l+1,rr=r-1;ans=b[rr/4+1][ll%4]^b[ll/4][ll%4];}else if (tmp==1){int ll=l,rr=r-1;ans=b[rr/4+1][ll%4]^b[ll/4][ll%4] ^b[(rr+1)/4+1][(ll+1)%4]^b[(ll+1)/4][(ll+1)%4];}else if (tmp==0){int ll=l,rr=r;ans=b[rr/4+1][ll%4]^b[ll/4][ll%4];}printf("%u\n",ans);}}return 0;
}
Problem L
Problem M
题意:
给你一个串strstrstr以及nnn个串stristr_istri,问你这nnn个串stristr_istri是否是串strstrstr的子序列。
分析:
直接暴力匹配显然会T,而又根据子序列的性质(下一个字符要匹配的字符ccc必定是在原串离上一个匹配成果的位置pospospos的最近的位置上),我们可以考虑对原串进行预处理。
我们设f[i][j]\text{f[i][j]}f[i][j]为:在原串iii位置上,离字符jjj最近的位置。我们可以用O(len)\mathcal{O}(len)O(len)的时间预处理出来这个,而在我们进行nnn个串的匹配时,我们不断在fff数组上去跳转即可。
代码:
#include <bits/stdc++.h>
#define maxn 100005
using namespace std;
char str[100005],p[1005];
int f[100005][300];
int len,n;
void init(){for(int i=0;i<len;i++){int flag=str[i];for(int j=i;j>=0;j--){if(f[j][flag]!=-1) break;f[j][flag]=i;}}
}
int main()
{//freopen("in.txt","r",stdin);scanf("%s",str);scanf("%d",&n);len=strlen(str);memset(f,-1,sizeof(f));init();while(n--){scanf("%s",p);int l=strlen(p);int cur=0;bool flag=0;for(int i=0;i<l;i++){if(f[cur][p[i]]==-1){flag=1;break;}cur=f[cur][p[i]]+1;}if(flag)puts("NO");else puts("YES");}return 0;
}
转载于:https://www.cnblogs.com/Chen-Jr/p/11007144.html
2019 The Preliminary Contest for ICPC China Nanchang National Invitational相关推荐
- The Preliminary Contest for ICPC China Nanchang National Invitational 南昌网络赛2019
题解不太详细,仅提供AC代码 A. PERFECT NUMBER PROBLEM #include <bits/stdc++.h> using namespace std;int main ...
- The Preliminary Contest for ICPC China Nanchang National Invitational
Problem A PERFECT NUMBER PROBLEM https://nanti.jisuanke.com/t/38220 题解:打表 /* *@Author: STZG *@Langua ...
- ICPC China Nanchang National Invitational - I. Max answer(线段树+ST)
题目链接 N个数字求一个区间使得∑i=li=ra[i]×∑i=li=rmin(a[i])\sum_{i=l}^{i=r} a[i] × \sum_{i=l}^{i=r}min(a[i])∑i=li=r ...
- ICPC China Nanchang National Invitational -- D. Match Stick Game(dp)
题目链接:https://nanti.jisuanke.com/t/38223 题意:有一堆火柴构成了一个加减法式子,你可以把火柴重新组合,要求数字个数和原来一样多,每个数字的位数和对应原数字位数一样 ...
- The Preliminary Contest for ICPC Asia Xuzhou 2019
小 银 川,给大爷们AK穿了 比赛地址:https://www.jisuanke.com/contest/3005?view=challenges A.(待补) B.1e9的数据范围,一开始从 ...
- The Preliminary Contest for ICPC Asia Nanjing 2019 B. super_log (广义欧拉降幂)
In Complexity theory, some functions are nearly O(1)O(1), but it is greater then O(1)O(1). For examp ...
- The Preliminary Contest for ICPC Asia Xuzhou 2019 徐州网络赛 XKC's basketball team
XKC , the captain of the basketball team , is directing a train of nn team members. He makes all mem ...
- H. Holy Grail(The Preliminary Contest for ICPC Asia Nanjing 2019题解)
题目链接 As the current heir of a wizarding family with a long history,unfortunately, you find yourself ...
- The Preliminary Contest for ICPC Asia Shanghai 2019 B. Light bulbs(卡了线段树空间的思维题)
传送门:https://nanti.jisuanke.com/t/41399 题目描述 There are NNN light bulbs indexed from 000 to N−1N−1N−1. ...
- The Preliminary Contest for ICPC Asia Shanghai 2019 Light bulbs
https://nanti.jisuanke.com/t/41399 离散差分 #include <iostream> #include <cstring> #include ...
最新文章
- 判断链表中是否有环(环形链表)
- MPB:甘肃省科学院祝英等-药用植物地下茎内生真菌的分离纯化及鉴定
- 网络知识:视频监控传输带宽与存储容量的计算方法
- 在Linux上构建ASP.NET环境-asp.net关注
- 解决Invalid `Podfile` file: no implicit conversion of nil into String
- win10电脑找不到xps查看器的详细解决步骤
- 计算机自带游戏在哪里,win10自带游戏,教您Win10纸牌游戏在哪
- Java项目服务器cpu占用100%解决办法
- 【腾讯TMQ】众测白皮书
- Chrome插件(UserScript)开发教程
- 对话Chris Jones:机器人行业的下一步应该这样走
- 21 年年度最佳开源软件!
- 【软件工程】决策表和决策树
- 文件上传之黑名单绕过
- 读取文件并输出,输出时将小写字母转为大写
- Xctf Reverse菜鸟题解之csaw2013reversing2
- 人工智能课程必背知识点
- 使用php读取大量列的excel数据
- 【愚公系列】2022年08月 微信小程序-view生成分享图片
- Adaptive AUTOSAR (AP) 平台设计(6)——通信管理