Codeforces Round #948 (Div. 2) C
题目链接:http://codeforces.com/contest/948/problem/C
题意:小花很喜欢雪 就像每一个没有来过东北的孩子一样 给出n天的状态 包括每天收集到雪的体积与该天的温度 问每天会融化多少体积的雪 每一天收集到的雪自成一堆 温度为x则每一堆雪融化x体积 如果剩余不到x体积 就全部融化完
思路:这道题很容易想到是解法就是n^2的跑 这个题的n可以达到1e5 n^2的跑会超时 想到一个优化就是开两个queue 不停地把还剩下雪的体积存起来 省去了检索体积为零的时间 但是在第11组的时候还是超时
题解:输入过程不用说了 我的想法是对每天的温度遍历一遍 正解是对每天的雪量遍历一遍 每天的雪使用二分查找找到这个雪在那一天会被用完 二分查找比扫一遍省很多时间 然后把这个范围内每天的ans加上对应的温度 最后一天加温度还是剩余的雪量需要特殊考虑 这样的话需要预处理出来温度的前缀和 用在二分查找里面 基本上是nlog的复杂度 但是感觉比上面那个想法省不了多少时间啊 上面那个也是每天的ans直接更新 更新的次数也是有多少雪对这一天有贡献就加上 不知道什么区别 先试试
原始想法 第十一组超时
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> #include<queue> using namespace std; long long n; long long v[100010]; long long t; long long ans; long long num; long long f; void read(long long &x){ x=0;char c=getchar(); while(c<'0' || c>'9')c=getchar(); while(c>='0' && c<='9'){ x=x*10+c-'0'; c=getchar(); } } void write(long long x){ if(x==0){putchar(48);return;} int len=0,dg[20]; while(x>0){dg[++len]=x%10;x/=10;} for(int i=len;i>=1;i--)putchar(dg[i]+48); } int main() { while( scanf("%I64d" , &n) != EOF ) { queue<int>Q[2]; for(long long i=0; i<n; i++) { read(v[i]); } for(long long i=0; i<n; i++) { read(t); ans = 0; num = i%2; Q[num].push(v[i]); while( !Q[num].empty() ) { f = Q[num].front(); Q[num].pop(); if( f >= t) { ans += t; Q[!num].push(f-t); } else { ans += f; } } if(i != 0) printf(" %I64d" , ans); else printf("%I64d" , ans); } printf("\n"); } return 0; }
写法不对 第四组就超时
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> using namespace std; int n , v[100010] , t[100010]; int sum[100010]; int ans[100010]; int fin(int x) { int l , r , mid , res; l = x; r = n; res = n+1; while( l<= r) { mid = (l+r)/2; // printf("%d......%d.....%d\n" , l , r , mid); if((sum[mid]-sum[x]+t[x]) >= v[x]) { res = mid; r = mid-1; } else { l = mid+1; } } return res; } int main() { sum[0] = 0; while( scanf("%d" , &n) != EOF ) { memset(ans , 0 , sizeof(ans)); for(int i=1; i<=n; i++) { scanf("%d" , &v[i]); } for(int i=1; i<=n; i++) { scanf("%d" , &t[i]); sum[i] = sum[i-1]+t[i]; } for(int i=1; i<=n; i++) { int r = fin(i); // printf(".......%d\n" , r); if(sum[r]-sum[i]+t[i]==v[i]) { for(int j=i; j<=r; j++) ans[j] += t[j]; } else { for(int j=i; j<r; j++) ans[j] += t[j]; ans[r] += v[i]-(sum[r-1]-sum[i]+t[i]); } if(i!=1) printf(" %d" , ans[i]); else if(i==1) printf("%d" , ans[i]); } } return 0; }
将数组修改为两个数组f[]数组记录会融化多少个完整的t体积 w记录会融化多少个剩余的体积 最后用f[]*t[]+w[] 会到十一组超时
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> using namespace std; long long n , v[100010] , t[100010]; long long sum[100010]; long long f[100010]; long long w[100010]; long long fin(long long x) { long long l , r , mid , res; l = x; r = n; res = n+1; while( l<= r) { mid = (l+r)/2; // printf("%I64d......%I64d.....%I64d\n" , l , r , mid); if((sum[mid]-sum[x]+t[x]) >= v[x]) { res = mid; r = mid-1; } else { l = mid+1; } } return res; } int main() { sum[0] = 0; while( scanf("%I64d" , &n) != EOF ) { memset(f , 0 , sizeof(f)); memset(w , 0 , sizeof(w)); for(long long i=1; i<=n; i++) { scanf("%I64d" , &v[i]); } for(long long i=1; i<=n; i++) { scanf("%I64d" , &t[i]); sum[i] = sum[i-1]+t[i]; } for(long long i=1; i<=n; i++) { long long r = fin(i); // printf(".......%I64d\n" , r); for(long long j=i; j<r; j++) f[j]++; w[r] += v[i]-(sum[r-1]-sum[i]+t[i]); if(i!=1) printf(" %I64d" , f[i]*t[i]+w[i]); else if(i==1) printf("%I64d" , f[i]*t[i]+w[i]); } } return 0; }
把f[]不设置成全部更新 只设置成更新断电 逐渐累加过去 这个是个小技巧 要记住 还有就是特殊样例
4
0 0 0 0
1 2 3 4
需要试一下
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> using namespace std; long long n; long long v[100010] , t[100010]; long long sum[100010]; long long f[100010] , w[100010]; long long fin(long long x) { v[x] += sum[x-1]; long long l = 1; long long r = n; long long mid; long long res; res = n+1; while( l <= r) { mid = (l+r)/2; if(sum[mid] >= v[x]) { res = mid; r = mid-1; } else { l = mid+1; } } return res; } int main() { sum[0] = 0; while( scanf("%I64d" , &n) != EOF ) { memset(f , 0 , sizeof(f)); memset(w , 0 , sizeof(w)); for(long long i=1; i<=n; i++) { scanf("%I64d" , &v[i]); } for(long long i=1; i<=n; i++) { scanf("%I64d" , &t[i]); sum[i] = sum[i-1]+t[i]; } long long zz; zz = 0; for(long long i=1; i<=n; i++) { long long r = fin(i); // printf("%I64d.........\n" , r); if(r>i && r != i) { f[i]++; f[r]--; w[r] += v[i]-sum[r-1]; } else { w[i] += v[i]-sum[i-1]; } zz += f[i]; if(i!=1) putchar(' '); printf("%I64d" , zz*t[i]+w[i]); } printf("\n"); } return 0; }