只A了几道水题,还好晋级了。
果然是水题,随便模拟一下就好了。为了题解完整性贴出来。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <set>
#include <vector>
#include <string.h>
using namespace std;
int a[1010];
int main(){
int t;
cin>>t;
while(t--){
int n; cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",a+i);
}
int q;
cin>>q;
int l,r;
for(int i=1;i<=q;i++){
scanf("%d%d",&l,&r);
int ans=-1;
for(int j=l;j<=r;j++){
if(a[j]>ans){
ans=a[j];
}
}
printf("%d\n",ans);
}
}
return 0;
}
02 Ponds
这题只要维护每个点的度就可以了,度小于2的点删掉,并减少相关点的度。用队列维护,删到不能再删,最后dfs统计一下奇数个点的连通分量。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <set>
#include <vector>
#include <string.h>
#include <queue>
using namespace std;
const int maxn=10010;
const int maxm=200010;
int a[maxn];
int head[maxn];
int pre[maxm];
int to[maxm];
int deg[maxn];
int tote;
bool vis[maxn];
bool removed[maxn];
int init(){
memset(head,-1,sizeof(head));
tote=0;
memset(removed,0,sizeof(removed));
memset(vis,0,sizeof(vis));
memset(deg,0,sizeof(deg));
}
void addedge(int u,int v){
to[tote]=v;
pre[tote]=head[u];
head[u]=tote++;
//
to[tote]=u;
pre[tote]=head[v];
head[v]=tote++;
}
#define ll long long
ll cur;
int dfs(int u){
vis[u]=1;
int re=1;
cur+=a[u];
for(int i=head[u];~i;i=pre[i]){
int v=to[i];
if(removed[v])continue;
if(vis[v])continue;
re+=dfs(v);
}
return re;
}
int main(){
int t;
cin>>t;
while(t--){
init();
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
scanf("%d",a+i);
}
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
deg[u]++;
deg[v]++;
}
queue<int> que;
for(int i=1;i<=n;i++){
if(deg[i]<2){
que.push(i);
}
}
while(que.size()){
int u=que.front(); que.pop();
removed[u]=1;
for(int i=head[u];~i;i=pre[i]){
int v=to[i];
if(removed[v])continue;
deg[v]--;
if(deg[v]<2){
que.push(v);
}
}
}
long long ans=0;
for(int i=1;i<=n;i++){
if(removed[i])continue;
if(vis[i])continue;
cur=0;
int cnt = dfs(i);
if(cnt&1){
ans+=cur;
}
}
cout<<ans<<endl;
}
return 0;
}
05 Travel
把询问离线,排序,先处理小的再处理大的。然后就是并查集,合并边小于等于当前询问的点,维护集合大小。对于每个集合来说,贡献就是size*(size-1)。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <set>
#include <vector>
#include <string.h>
#include <queue>
using namespace std;
const int maxn=20010;
const int maxm=100010;
const int maxq=5010;
#define ll long long
struct edge{
int u,v,len;
edge(int u,int v,int len):u(u),v(v),len(len){
}
edge(){
}
bool operator<(const edge& other)const{
return len<other.len;
}
}edges[maxm];
struct Q{
int qq;
int id;
ll ans;
bool operator<(const Q& other)const{
return qq<other.qq;
}
}Qs[maxq];
ll ans[maxq];
int shi_si[20005];
int shi_f[20005];
void init(int n){
for(int i=1;i<=n;i++){
shi_si[i]=1;
shi_f[i]=i;
}
}
int get_fa(int x){
if(shi_f[x]==x){
return x;
}else{
int re=get_fa(shi_f[x]);
shi_f[x]=re;
return re;
}
}
int unit(int a,int b){
int fa = get_fa(a);
int fb = get_fa(b);
if(shi_si[fa] > shi_si[fb]){
shi_f[fb] = fa;
shi_si[fa] += shi_si[fb];
}
else{
shi_f[fa] = fb;
shi_si[fb] += shi_si[fa];
}
}
ll calc(ll sz){
return sz*(sz+1);
}
int main(){
int t;
cin>>t;
while(t--){
int n,m,q;
cin>>n>>m>>q;
init(n);
for(int i=0;i<m;i++){
int u,v,len;
scanf("%d%d%d",&u,&v,&len);
edges[i]=edge(u,v,len);
}
sort(edges,edges+m);
for(int i=1;i<=q;i++){
scanf("%d",&Qs[i].qq);
Qs[i].id=i;
}
sort(Qs+1,Qs+1+q);
int pos=0;
ll curans=0;
for(int i=1;i<=q;i++){
while(edges[pos].len<=Qs[i].qq&&pos<m){
int u=edges[pos].u;
int v=edges[pos].v;
int sizeu=0;
int sizev=0;
int fu=get_fa(u);
int fv=get_fa(v);
pos++;
if(fu==fv){
continue;
}
curans-=calc(shi_si[fu]);
curans-=calc(shi_si[fv]);
unit(u,v);
int fff=get_fa(u);
curans+=calc(shi_si[fff]);
}
Qs[i].ans=curans;
}
for(int i=1;i<=q;i++){
int target=Qs[i].id;
ans[target]=Qs[i].ans;
}
for(int i=1;i<=q;i++){
printf("%I64d\n",ans[i]);
}
}
return 0;
}
这题卡着时限过的。。其实很简单,就是用优先队列模拟过程,开门时间用数组来存比较好,注意最后会全放进去。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <set>
#include <vector>
#include <string.h>
#include <queue>
#include <map>
using namespace std;
int k, m, q;
int t[150005];
int p[150005];
int ans[150005];
struct node {
char s[205];
int id;
int v;
bool operator < (const node& a) const {//?
if(v == a.v) return a.id < id;
return v < a.v;
}
}person[150005];
int open[150005];
void init(){
memset(open,0,sizeof(open));
}
int main() {
int T;
cin >> T;
while(T --) {
init();
cin >> k >> m >> q; //人数 开门数 查询数
for(int i = 1; i <= k; i ++) {
scanf("%s",person[i].s);
scanf("%d", &person[i].v);
person[i].id = i;
}
for(int i = 1; i <= m; i ++) {
int t,p;
scanf("%d %d", &t, &p);
open[t]+=p;
}
open[k]=k;
priority_queue<node> que;
int rank=1;
for(int i=1;i<=k;i++){
que.push(person[i]);
while(open[i]--){
if(que.size()==0){
break;
}
node tmp=que.top(); que.pop();
ans[rank++]=tmp.id;
}
}
for(int i = 1; i <= q; i ++) {
int t;
scanf("%d", &t);
printf("%s",person[ans[t]].s);
if(i != q) {
printf(" ");
}
else {
printf("\n");
}
}
}
return 0;
}
首先给的结构是二叉树,所以左子树在东边,右子树在西边。对于每个子树,根据根的大小就能够知道它的左右子树的大小。递归一下,找出以每个节点为根的左子树大小就可以模拟走路过程了。从根开始走,如果根小了往西,否则往东。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <set>
#include <vector>
#include <string.h>
#include <queue>
#include <map>
using namespace std;
const int maxn=1010;
int rangel[maxn];
int ranger[maxn];
int a[maxn];
int lsize[maxn];
void fun(int root,int ll,int rr){
if(ll==rr)return;
rangel[root]=ll;
ranger[root]=rr;
lsize[root]=a[root]-ll;
if(a[root]!=ll)fun(root+1,ll,ll+lsize[root]-1);
if(a[root]!=rr)fun(root+lsize[root]+1,a[root]+1,rr);
}
int main() {
int T;
cin >> T;
while(T--){
int n;
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",a+i);
}
fun(1,1,n);
int q;
cin>>q;
while(q--){
int b;
scanf("%d",&b);
int cur=1;
while(1){
if(a[cur]==b){
printf("\n");
break;
}else if(a[cur]>b){
cur++;
printf("E");
}else{
cur+=lsize[cur]+1;
printf("W");
}
}
}
}
return 0;
}
这题学弟过的。数论渣表示并不会Orz。一会补题。
后缀数组。简单来说求的就是字符串的最大字典序,这可以根据SA的rank数组得到。正序重叠跑SA,逆序重叠再跑SA。要注意题目的各种要求,优先起点下标小,优先顺时针。为了做到这一点,需要在逆串重叠后加一个大字符,在正串最大和逆串最大相等的情况下要特判。需要考虑许多细节,见代码。这题最后2min绝杀,真心爽。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <set>
#include <vector>
#include <string.h>
#include <queue>
#include <map>
using namespace std;
const int Max=40010;
char str[Max];
char old[Max];
int num[Max];
int sa[Max], Rank[Max], height[Max];
int wa[Max], wb[Max], wv[Max], wd[Max];
int cmp(int *r, int a, int b, int l){
return r[a] == r[b] && r[a+l] == r[b+l];
}
void da(int *r, int n, int m){ // 倍增算法 r为待匹配数组 n为总长度 m为字符范围
int i, j, p, *x = wa, *y = wb, *t;
for(i = 0; i < m; i ++) wd[i] = 0;
for(i = 0; i < n; i ++) wd[x[i]=r[i]] ++;
for(i = 1; i < m; i ++) wd[i] += wd[i-1];
for(i = n-1; i >= 0; i --) sa[-- wd[x[i]]] = i;
for(j = 1, p = 1; p < n; j *= 2, m = p){
for(p = 0, i = n-j; i < n; i ++) y[p ++] = i;
for(i = 0; i < n; i ++) if(sa[i] >= j) y[p ++] = sa[i] - j;
for(i = 0; i < n; i ++) wv[i] = x[y[i]];
for(i = 0; i < m; i ++) wd[i] = 0;
for(i = 0; i < n; i ++) wd[wv[i]] ++;
for(i = 1; i < m; i ++) wd[i] += wd[i-1];
for(i = n-1; i >= 0; i --) sa[-- wd[wv[i]]] = y[i];
for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i ++){
x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1: p ++;
}
}
}
void calHeight(int *r, int n){ // 求height数组。
int i, j, k = 0;
for(i = 1; i <= n; i ++) Rank[sa[i]] = i;
for(i = 0; i < n; height[Rank[i ++]] = k){
for(k ? k -- : 0, j = sa[Rank[i]-1]; r[i+k] == r[j+k]; k ++);
}
}
int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
scanf("%s",str);
for(int i=0;i<n;i++){
str[i+n]=str[i];
}
str[n*2]='\0';
int i,m=30;
int len=2*n;
for(int i=0;i<=len;i++){
old[i]=str[i];
}
for(i=0;i<=len;i++)num[i]=str[i]-'a'+1;
num[len]=0;
da(num, len + 1, m);
calHeight(num, len);
int MMMAX=-1;
int ans=0;
for(int i=0;i<n;i++){
if(Rank[i]>MMMAX){
MMMAX=Rank[i];
ans=i;
}
}
reverse(str,str+len);
str[len]='z'+1;
str[len+1]='\0';
len++;
for(i=0;i<=len;i++)num[i]=str[i]-'a'+1;
num[len]=0;
da(num, len + 1, m);
calHeight(num, len);
MMMAX=-1;
int ans2=0;
for(int i=0;i<n;i++){
if(Rank[i]>MMMAX){
MMMAX=Rank[i];
ans2=i;
}
}
int dir=0;
bool eq=0;
for(int i=0;i<n;i++){
if(str[ans2+i]>old[ans+i]){
dir=1;
break;
}else if(str[ans2+i]<old[ans+i]){
break;
}else{
if(i==n-1){
eq=1;
}
}
}
ans2=n-ans2-1;
if(eq&&ans2<ans){
dir=1;
}
if(dir==0){
printf("%d %d\n",ans+1,dir);
}else{
printf("%d %d\n",ans2+1,dir);
}
}
return 0;
}
本文分享了作者在ACM竞赛中的解题经验,包括如何快速解决简单的“水题”,利用优先队列模拟过程,使用并查集处理图论问题,通过后缀数组寻找最优解等实用技巧。
1480

被折叠的 条评论
为什么被折叠?



