标签:strong getch stream 模拟 family end mes top clu
T1/Codeforces 975C
很简单,直接前缀和然后二分找答案即可,注意超过最大挡箭数的时候会“全员复活” ······
#include<bits/stdc++.h> using namespace std; inline long long read(){ long long x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=(x<<3)+(x<<1)+ch-‘0‘;ch=getchar();} return x*f; } #define MN 200005 int n,q; long long a[MN],k[MN]; int main(){ n=read(),q=read(); for(int i=1;i<=n;i++) a[i]=read()+a[i-1]; for(int i=1;i<=q;i++) k[i]=read(),k[i]=k[i]+k[i-1]>=a[n]?0:k[i]+k[i-1]; for(int i=1;i<=q;i++){ cout<<n-(upper_bound(a+1,a+n+1,k[i])-a-1)<<endl; } return 0; }
T2/POJ 1704
~博弈论,题意是有一行的棋格,Bob和Georgia比赛玩,没人每次可以把任意棋子像左边移动任意的长度,问先手胜还是后手胜。
怎么说,这是最基础的博弈论了吧,把相邻的两个棋子分成同一组,将它们之间的间隔当作SG值,直接^在一起,当结果为0时是必败态,否则是必胜态。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=(x<<3)+(x<<1)+ch-‘0‘;ch=getchar();} return x*f; } #define MP 10005 int a[MP],n,T; int main(){ T=read(); while(T--){ n=read(); for(int i=1;i<=n;i++) a[i]=read(); sort(a+1,a+n+1); int sum=0; for(int i=n;i>0;i-=2) sum^=a[i]-a[i-1]-1; printf("%s\n",sum?"Georgia will win":"Bob will win"); } return 0; }
T3/POJ 3709
~斜率优化。
题意:给你一堆数,你可以随意的减小它们数值,使得每个数的出现次数不少于k的情况下,问最小的代价是多少。
其实也很少打斜率的题,而且dp本来就是我的弱项,能够A掉这道题,只能说是lucky吧。。。
显然可以得到如下递推式:
f[i]=min{f[j]+a[j+2]-a[j+1]+a[j+3]-a[j+1]+...+a[i]-a[j+1],0<=j<=i-k+1} O(n^3)
用前缀和优化,得到:
f[i]=min{f[j]+S[i]-S[j]-(i-j)*a[j+1],0<=j<=i-k+1} O(n^2)
考虑对于两个数 x 和 y ,(x<y),如果x优于y,我们必须要满足的条件是:
f[x]-S[x]-(i-x)*a[x+1]<f[y]-S[y]-(i-y)*a[y+1]
整理可得:
f[x]-f[y]-S[x]+S[y]+x*a[x+1]-y*a[y+1]<i*(a[x+1]-a[y+1])
所以呢,随着i的增加,等式右边的值会越来越小,队首的元素可能会不再优于后面的元素,所以我们需要先排除队首的元素问题:
ll get(int x){ while(top>tail&&dy(q[tail],q[tail+1])>x*dx(q[tail],q[tail+1])) tail++; return q[tail]; }
然后我们继续,此时的f[i]值等于,当j等于队首元素值时上式的值。
单调队列的进队操作很显然,令对尾两数为top-1 和 top,将入队的为x,如果x优于top的程度比top优于top-1的程度还厉害,即x会比top更早的优于前一个元素,那么直接--top吧。
void ins(int x){ while(top>tail&&dy(q[top-1],q[top])*dx(q[top],x)>=dy(q[top],x)*dx(q[top-1],q[top]))--top; q[++top]=x; }
本质上呢,就是一个斜率优化。
//#include<bits/stdc++.h> #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=(x<<3)+(x<<1)+ch-‘0‘;ch=getchar();} return x*f; } #define MN 500005 #define ll long long ll T,k,n,f[MN]; struct sq{ll sm,a;}l[MN]; ll top,tail,q[MN]; ll dx(int x,int y){return l[x+1].a-l[y+1].a;} ll dy(int x,int y){return f[x]-f[y]-l[x].sm+l[y].sm+x*l[x+1].a-y*l[y+1].a;} ll get(int x){ while(top>tail&&dy(q[tail],q[tail+1])>x*dx(q[tail],q[tail+1])) tail++; return q[tail]; } void ins(int x){ while(top>tail&&dy(q[top-1],q[top])*dx(q[top],x)>=dy(q[top],x)*dx(q[top-1],q[top]))--top; q[++top]=x; } int main(){ T=read(); while(T--){ n=read(),k=read(); for(int i=1;i<=n;i++) l[i].a=read(),l[i].sm=l[i].a+l[i-1].sm; q[top=tail=1]=0; for(int i=1;i<=n;i++){ int from=get(i),to=i-k+1; f[i]=f[from]+l[i].sm-l[from].sm-1LL*(i-from)*l[from+1].a; if(to>=k) ins(to); } cout<<f[n]<<endl; } return 0; }
T4/POJ 2932
题目的意思很好懂吖。一些不会相交也不相切的圆,找到所有不内含于其他圆的圆。
因为题目内的圆不存在相交的情况, 所以直接储存每个圆的左端点和右端点的x坐标,然后从左扫到右。
我们在从左向右平移与y轴平行的直线的同时,维护与扫面线相交的最外层的圆的集合。从左到右移动中,只有扫面线移动到圆的左右两端时,
圆与扫描线的相交关系才会发生变化,因此我们先将所有这样的x坐标枚举出来并排好序。如果满足是最外面的圆,就储存在set里面。
如何判断满足呢,就是对每一个x,如果是左端点的x坐标就来判断其对应的圆,是否是在set中储存的圆内,如果不是 ,就存到set中。如果是右端点的x坐标,就pop出该圆。
好像:是不是很难呢?
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <set> #include <algorithm> using namespace std; const int N = 40005; int n; double x[N],y[N],r[N]; bool inside(int i, int j){ double dx = x[i]-x[j]; double dy = y[i]-y[j]; return dx*dx+dy*dy <= r[j]*r[j]; } void solve(){ vector<pair<double,int> > events;//圆的左右两端的x坐标 for(int i = 0; i < n; i++){ events.push_back(make_pair(x[i]-r[i],i));//圆的左端 events.push_back(make_pair(x[i]+r[i],i+n));//圆的右端 } sort(events.begin(), events.end()); //平面扫描 set<pair<double, int> > outers;//与扫面线相交的最外层的圆的集合 vector<int>ans;//最外层圆的列表 for(int i = 0; i < events.size(); i++){ int id = events[i].second % n; if(events[i].second < n){//扫描到左端 set<pair<double, int> >::iterator it = outers.lower_bound(make_pair(y[id],id)); if(it != outers.end() && inside(id, it->second)) continue; if(it != outers.begin() && inside(id, (--it)->second)) continue; ans.push_back(id); outers.insert(make_pair(y[id], id)); } else{//扫描到右端 outers.erase(make_pair(y[id], id)); } } sort(ans.begin(), ans.end()); int len = ans.size(); printf("%d\n", len); for(int i = 0; i < len; i++){ printf("%d%c",ans[i]+1,i+1 == len?‘\n‘ : ‘ ‘); } } int main(){ while(~scanf("%d",&n)){ for(int i = 0; i < n; i++) scanf("%lf%lf%lf", &r[i],&x[i],&y[i]); solve(); } return 0; }
At last,
happy rank 1!
来自PaperCloud的博客,未经允许,请勿转载,TKS。
标签:strong getch stream 模拟 family end mes top clu
原文地址:https://www.cnblogs.com/PaperCloud/p/9032919.html