[原创]BNU Training 2017.07.20 【(2+1+0.233)/11】[待补]
2017-07-20 21:19:45 Tabris_ 阅读数:581
博客爬取于2020-06-14 22:39:35以下为正文
版权声明:本文为Tabris原创文章,未经博主允许不得私自转载。https://blog.csdn.net/qq_33184171/article/details/75578185
#首先膜一发qls
题目质量很高,看样子是训练题而不是套题 ,没有特别简单的题目,
然后再次感到自己菜的一逼
A CodeChef SPCLN Cleaning the Space ——————————————————————————————————————————
B CodeChef PREFIXOR Prefix XOR ——————————————————————————————————————————
C CodeChef WIQ Waiting in a Queue —————————————————————————————————————————— 给你一个队列,每个人要做一个事情,他们分别在b [ i ] b[i] b [ i ] 时刻准备好,并在轮到他的时候花费a [ i ] a[i] a [ i ] 时间完成. 每次要花费一分钟检查队头的人准没准备好,如果队头的人准备好了就开始做,做完就离开,否则去队尾.
这个和CF div.2 424 E 比较像,但是需要多维护这些人的时间什么的。复杂一点
首先能想到维护一个当前的时刻 那么能想到 每次操作 处理一个人,那么这个人一定是接下来的人中第一个准备好的, 于是 考虑每次只维护这些能准备好的人,将这些人的序号放入set 中,每次遍历一轮,同时维护当前时刻将能准备好的在加入到set 中, 计算两个人之间花了多少时间用一个树状数组 维护一下即可
设立一个当前时间, 在当前时间下 走过一圈能准备好的 加入set 然后处理这些, 因为加入一个元素到set后,当前时间不处理 下一次也一定处理了,所以最多也就被访问两遍 总复杂度O ( n log n ) O(n \log n ) O ( n log n )
set怎么这么强大啊 基本可代替SPLAY啊。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 # include <bits/stdc++.h> # define xx first # define yy second # define mp make_pair # define pb push_back # define fill( x, y ) memset( x, y, sizeof x ) # define copy( x, y ) memcpy( x, y, sizeof x ) using namespace std; typedef long long LL; typedef pair < int, int > pa; inline LL read() { LL sc = 0, f = 1; char ch = getchar(); while(ch<'0'||ch>'9') {if(ch =='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9') sc=sc*10+ch-'0',ch=getchar(); return sc * f; } const int MAXN = 1000005; int n, bit[MAXN], lef, cur; LL a[MAXN], b[MAXN], ans[MAXN], tim; set < int > S; pair<LL,int>c[MAXN]; inline int lowbit(int x) {return x & -x;} inline void modify(int x, int v) {for(;x<=n;x+=lowbit(x))bit[x]+=v;} inline int query(int x) {int ret = 0;for(;x;x-=lowbit(x))ret+=bit[x];return ret;} inline void upd(){ while(cur<=n&&tim+lef>=c[cur].xx) S.insert( c[ cur++ ].yy ); } inline void solve() { n = lef = read(); tim = 0;cur = 1; for( int i = 1 ; i <= n ; i++ ) a[i]=read(),bit[i]=0; for( int i = 1 ; i <= n ; i++ ) b[i]=read()-1,modify(i,1),c[i]=mp(b[i],i); sort(c+1,c+n+1); // for(int i=1;i<=n;i++) printf("%lld %d\n",c[i].first,c[i].second); while(lef){ if(!S.size()&&cur<=n&&tim+lef<=c[cur].xx) tim+=(c[cur].xx-tim)/lef*lef; //轮到下一个准备好的人的时间 upd(); int last = 0; set<int>::iterator it = S.begin(); while( it != S.end() ) { tim += query( *it ) - query(last); last = *it; upd(); if( tim > b[ *it ] ) { ans[ *it ] = tim += a[ *it ]; upd(); lef--; it++; S.erase( last ); modify( last, -1 ); } else it++; } tim += query( n ) - query( last ); } for( int i = 1 ; i <= n ; i++ ) printf( "%lld%c", ans[ i ], i == n ? '\n' : ' ' ); } int main() { for( int T = read() ; T ; T-- ) solve(); return 0; }
D CodeChef FOURPTS Four Points —————————————————————————————————————————— 给你四个点,问你有没有一个三角形能经过这四个点,能的话输出YES和任意一个这样的三角形,否则输出NO
没写代码,口胡一下
首先特判一下有三点共线的情况, 有的话输出, 判断这四个点构成的四边形是凹的还是凸的,凹的话一定是NO输出 如果是凸的一定有,然后找这个三角形, 找三角形的办法是先对点排个序,假设(a,b,c,d)是顺时针顺序的,则枚举a b ⃗ 和 a d ⃗ 或 2 a d ⃗ \vec {ab}和\vec{ad}或2\vec{ad} ab 和 a d 或 2 a d 找a b ab ab 和d c dc d c 的交点即可 找到三角形第三个点,而另外两个点是a , d a,d a , d 还是b , c b,c b , c 看这两条线哪个长就行. E CodeChef ANCESTOR Ancestors in Two Trees ——————————————————————————————————————————
F CodeChef CHEFPRAD Chef and Pairs —————————————————————————————————————————— 有两个序列A,B,在[ − 2 9 , 2 9 ] [-2^9,2^9] [ − 2 9 , 2 9 ] 选择一个数使A数组的每一个元素减去这个数,然后根据a b s ( a i − b j ) < = k abs(a_i-b_j)<=k ab s ( a i − b j ) <= k 建边,然后求最大二分匹配,问你这个最大二分匹配是多少,
首先考虑到应该通过一种什么样的方式枚举这些数,然后求这个二分匹配哦,但是光二分匹配的复杂度就已经O(VE)了, 所以这部分一定能优化
然后考虑到,这是一些序列,而建边的方式又是根据距离,所以这相当于在直线上的匹配,
然后发现对于数组a中的每个元素,如果要是匹配最大,左边的a一定尽量选左边的b, 对于b同理
那么我们可以枚举a和b数组,从左向右找, 那么分析如果当前a b s ( a i − b j ) < = k abs(a_i-b_j)<=k ab s ( a i − b j ) <= k ,那么i + + , j + + i++,j++ i + + , j + + ,否则的话 就选这两个中靠右的留下,因为靠左的已经不能在和他匹配的了
所以这部分就可以用O ( n + m ) O(n+m) O ( n + m ) 的复杂度处理.
然后想到如何枚举这些数
考虑 这个数的选取最好能使一个a[i]和b[j]匹配上,所以可以枚举a[i]-b[j]
注意的是这两个数能匹配上的点恰好是a[i]-b[j]-e 所以枚举这个就好了
复杂度为O ( n m ) O(nm) O ( nm )
总复杂度O ( T n m ( n + m ) ) O(Tnm(n+m)) O ( T nm ( n + m ))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 # include<stdio.h> # include<string.h> # include<algorithm> using namespace std; # define ll long long int ll a[1500]; ll b[1500]; ll dist[450][450]; ll temp[450]; int n,m; ll e; int Slove(ll x) { for(int i=1; i<=n; i++) temp[i]=a[i]-x; int ans = 0; for(int i=1,j=1;i<=n&&j<=m;){ if(abs(temp[i]-b[j])<=e) i++,j++,ans++; else if(temp[i]<b[j]) i++; else j++; } // printf("%lld %d\n",x,ans); return ans; } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d%lld",&n,&m,&e); for(int i=1; i<=n; i++)scanf("%lld",&a[i]); sort(a+1,a+1+n); for(int i=1; i<=m; i++)scanf("%lld",&b[i]); sort(b+1,b+1+m); for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { dist[i][j]=(a[i]-b[j]); } } int ans=0; ans=max(Slove(0),ans); for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { ans=max(Slove(dist[i][j]-e),ans); } } printf("%d\n",ans); } }
G CodeChef PLUSMUL Add or Multiply —————————————————————————————————————————— 给你一个序列,两个相邻的数之间可以放一个乘号 或加号 ,问你所有可能下 放完符号的序列 运算完的结果总和是多少
首先考虑每个数的贡献,但是因为有乘法在,容易重复,于是变成求以每个数结尾的单项式 对结果的贡献
于是设 f[i] 表示以第i个数结尾的单项的系数 即:f [ i ] ∗ a [ i ] ∗ 2 ( n − i − 1 ) f[i]*a[i]*2^{(n-i-1)} f [ i ] ∗ a [ i ] ∗ 2 ( n − i − 1 ) 为对结果的贡献
f[i]转移就是
f [ 1 ] = 0 f [ 2 ] = a [ 1 ] f [ i ] = f [ i − 1 ] ∗ a [ i − 1 ] + a [ i − 1 ] ∗ 2 i − 3 , i > = 3 f[1]=0 \\ f[2]=a[1]\\ f[i]=f[i-1]*a[i-1] + a[i-1]*2^{i-3},i>=3 f [ 1 ] = 0 f [ 2 ] = a [ 1 ] f [ i ] = f [ i − 1 ] ∗ a [ i − 1 ] + a [ i − 1 ] ∗ 2 i − 3 , i >= 3
然后加上每个数作为加数 的贡献,
算一下就好了 能发现除了首尾 都是× 2 n − 3 , 减 1 是有 n − 1 的符号 , 去掉两边的符号再减 2 \times 2^{n-3},减1是有n-1的符号,去掉两边的符号再减2 × 2 n − 3 , 减 1 是有 n − 1 的符号 , 去掉两边的符号再减 2
最后计算结果 看代码把 因为是从3开始算得 所以1和2的情况要特判
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 # include <bits/stdc++.h> typedef long long int LL; using namespace std; const int N = 100000+7; const int MOD = 1e9+7; LL a[N],f[N],q2[N]; LL qq2(int x){ return (x>=0)?q2[x]:1; } int main(){ q2[0]=1; for(int i=1;i<N;i++) q2[i]=(q2[i-1]*2)%MOD; int _,n;scanf("%d",&_); while(_--){ scanf("%d",&n); pre[0]=1;a[0]=1; for(int i=1;i<=n;i++) scanf("%lld",&a[i]); if(n==1) { printf("%d\n",a[1]); continue; } if(n==2){ printf("%d\n",a[1]+a[2]+a[1]*a[2]); continue; } LL ans = 0; f[1]=0,f[2]=a[1]; for(int i=3;i<=n;i++){ f[i]=f[i-1]*a[i-1]%MOD + a[i-1]*q2[i-3]%MOD; f[i]%=MOD; } for(int i=1;i<=n;i++){ ans+=a[i]*q2[n-3]%MOD;ans%=MOD; ans+=a[i]*f[i]%MOD*qq2(n-i-1)%MOD;ans%=MOD; } ans += (a[1]+a[n])*q2[n-1-2]%MOD;ans%=MOD; printf("%lld\n",ans); } return 0; }
H CodeChef GQUERY Game Revisited ——————————————————————————————————————————
I CodeChef MEXDIV Mex division ——————————————————————————————————————————
J CodeChef ROBOTDAG Robots in a DAG ——————————————————————————————————————————
K CodeChef BLACKCOM Black Nodes in Subgraphs ——————————————————————————————————————————