2018.9.22 Bubble Cup 11-Finals(Online Mirror,Div.2)

感受了一下ACM的感觉,然后被神题和神犇们暴踩了

夭寿啦,机房大佬非法组队啊

比赛前i207M插的“怕不是不到九点就要弃疗”的flag成功生效

一开始先扫了一遍题,我一开始以为A题是个扫一遍的题,然后发现自己naive了,遭到了wyt的嘲讽,不过i207M觉得这是个权值数据结构,然而我太蒻了并不会,于是他就去写了。然后就听到Zhang_RQ说B题是个圆方树,果断弃了,终于发现C很可做,然后我写了一发过掉了。然后i207M交了一发$A$挂了,发现他读错题了,然后就听到zhoutb2333说这是个CDQ,我们又(?)果断弃掉了=。=

然后wyt跟我说F是个大根堆?(我**居然信了)

然后他T了,我觉得是他写萎了,我也按他的思路写了一发

然后我也T了,发现他根本不是写萎了,是想萎了,这不是扫一遍就完了吗=。=

看了看发现H题有不少(十几个?)人A了,我和i207M就去看,转化了一下题面发现这好像是个计数问题。i207M立刻切出来了(!),然而蒟蒻的我一时并没完全听懂,我说我先码着你再想想,码到一半他又跟我说了说终于听懂了,然后测一发样例

哇,挂啦

i207M发现漏了一种情况,然后他改了一处就过掉了,我还在问问问,不过后来想明白了

然后我们就开始找可做题(其实已经没了=。=),他看上了$E$我看上了$G$,然后他说完$E$我们感觉没什么特别明显的思路,不过他觉得$G$很可做,然后我就去看$J$了,感觉$J$是个特别可做的数位DP。结果讨论了半天发现连状态都设不下,于是暂时弃掉了,又去刚$G$结果也无果,最后我们就在九点弃疗了=。=

整个比赛还是很欢乐的,这次只放我们切的三道水题了2333

Update on 2018.9.28:准备更新A和B

Update on 2018.10.9:咕咕了一个多星期之后终于更了A,B还在咕咕咕的路上(滚那

A.AI Robots

考场时众多大佬用CDQ/树套树碾过去了,事实上这个题并不难......

我们将机器人按视力从高到低排序,然后依次考虑每个机器人,把机器人们加入一棵权值线段树。这样如果新加入的机器人能看到之前的机器人的话,之前的这些机器人也能看到新加入的机器人,用线段树维护区间和,就可以直接计算贡献了。现在的问题是智商的差距如何考虑,因为智商的差距非常小,我们可以直接枚举每个智商的差值来统计答案,复杂度$O(nklog$ $n)$。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=100005;
 6 struct a
 7 {
 8     int p,e,q;
 9 }rob[N];
10 int un1[N],un2[N];
11 int root[N],val[18*N],son[18*N][2];
12 int n,m,l1,l2,cnt,tot;
13 long long ans;
14 bool cmp(a x,a y)
15 {
16     return x.e>y.e;
17 }
18 void add(int &nde,int l,int r,int pos)
19 {
20     if(!nde) nde=++tot; val[nde]++;
21     if(l==r) return ; int mid=(l+r)/2;
22     if(pos<=mid) add(son[nde][0],l,mid,pos);
23     else add(son[nde][1],mid+1,r,pos);
24 }
25 long long query(int nde,int l,int r,int nl,int nr)
26 {
27     if(!nde) return 0;
28     if(l>=nl&&r<=nr) return val[nde]; 
29     int mid=(l+r)/2; long long ret=0;
30     if(nl<=mid) ret+=query(son[nde][0],l,mid,nl,nr);
31     if(mid<nr) ret+=query(son[nde][1],mid+1,r,nl,nr);
32     return ret;
33 }
34 int main ()
35 {
36     scanf("%d%d",&n,&m);
37     for(int i=1;i<=n;i++)
38     {
39         scanf("%d%d%d",&rob[i].p,&rob[i].e,&rob[i].q);
40         un1[i]=rob[i].p,un2[i]=rob[i].q;
41     }
42     sort(rob+1,rob+1+n,cmp);
43     sort(un1+1,un1+1+n),l1=unique(un1+1,un1+1+n)-un1-1;
44     sort(un2+1,un2+1+n),l2=unique(un2+1,un2+1+n)-un2-1;
45     for(int i=1;i<=n;i++)
46     {
47         rob[i].p=lower_bound(un1+1,un1+1+l1,rob[i].p)-un1;
48         rob[i].q=lower_bound(un2+1,un2+1+l2,rob[i].q)-un2;
49     }
50     for(int i=1;i<=n;i++)
51     {
52         for(int j=-m;j<=m;j++)
53         {
54             int pos=lower_bound(un2+1,un2+1+l2,un2[rob[i].q]+j)-un2;
55             int ll=lower_bound(un1+1,un1+1+l1,un1[rob[i].p]-rob[i].e)-un1;
56             int rr=upper_bound(un1+1,un1+1+l1,un1[rob[i].p]+rob[i].e)-un1-1;
57             if(un2[pos]==un2[rob[i].q]+j)
58                 ans+=query(root[pos],1,l1,ll,rr);
59         }
60         add(root[rob[i].q],1,l1,rob[i].p);
61     }
62     printf("%lld",ans);
63     return 0;
64 }
View Code

C.Space Formula

首先把最大的$b$配给我们的选手,然后(按其他选手实力)从大到小贪心。如果这个人配上最小的都能赢我们就把最大的给他,减小之后的压力,否则找一个尽可能大的给他让他打不过我们,易知这样最优(详见ZJOI 泡泡堂)

 1 #include<set>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int N=200005;
 7 long long a[N],b[N],aa[N],bb[N];
 8 long long n,d,l1,l2,p1,p2,rnk;
 9 multiset<long long> st;
10 multiset<long long>::iterator it;
11 int main ()
12 {
13     scanf("%lld%lld",&n,&d); 
14     for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
15     for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
16     long long forc=a[d]+b[1];
17     for(int i=1;i<=n;i++) if(i!=d) aa[++l1]=a[i];
18     for(int i=n;i>=2;i--) st.insert(b[i]); rnk=1;
19     for(int i=1;i<=l1;i++) 
20     {
21         if(aa[i]>forc) rnk++,it=st.end(),it--,st.erase(it);
22         else
23         {
24             if(aa[i]+(*(st.begin()))>forc) {rnk++,it=st.end(),it--,st.erase(it);continue;}
25             long long res=forc-aa[i];it=st.upper_bound(res);
26             it--; st.erase(it);
27         }
28     }
29     printf("%lld",rnk);
30     return 0;
31 }
View Code

F.Splitting money

水题

 1 #include<queue>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 long long bit[200005];
 7 long long n,maxx,c,ans;
 8 int main ()
 9 {
10     scanf("%lld",&n);
11     for(int i=1;i<=n;i++)
12         scanf("%lld",&bit[i]);
13     scanf("%lld%lld",&maxx,&c);
14     for(int i=1;i<=n;i++) 
15         if(bit[i]>maxx)
16             ans+=((long long)ceil((double)(bit[i]-maxx)/(double)(maxx+c)))*c;
17     printf("%lld",ans);
18     return 0;
19 }
View Code

H.Palindrome Pairs

伪装成字符串的计数题

因为两个串组合后我们可以随便排列字母,所以能否回文显然只跟每个字母在每个串中出现的次数的奇偶性有关。我们把出现奇数次的字母这位看成$1$,出现偶数次的字母这位看成$0$,这样每个串就可以表示为一个$26$位的零一串,拼起来可以看做异或,回文就是异或后只有一位为$1$。因为要求无序的,所以我们直接开个$map$计每种串出现的次数,每次枚举一位统计上当前串这位取反得到串的个数,最后加上这个串出现的次数即可。

 1 #include<map>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int N=100005,M=1000005;
 7 map<int,long long> cnt;
 8 char rd[M];
 9 int n,len;
10 long long ans;
11 int main ()
12 {
13     scanf("%d",&n);
14     for(int i=1;i<=n;i++)
15     {
16         scanf("%s",rd);
17         int str=0;
18         int len=strlen(rd);
19         for(int j=0;j<len;j++)
20             str^=(1<<(rd[j]-'a'));
21         ans+=cnt[str];
22         for(int j=0;j<26;j++)
23             ans+=cnt[str^(1<<j)];
24         ++cnt[str];
25     }
26     printf("%lld",ans);
27     return 0;
28 }
View Code
原文地址:https://www.cnblogs.com/ydnhaha/p/9696912.html