拖了一周才完成的题解,抛出一个可爱的表情 (っ'-')╮ =͟͟͞͞❤️。对我来说E、F比较难,都是线段树的题,有点久没写了。

A - Infinite Sequence

CodeForces - 675A

公差为c,首项为a的等差数列是否有一项等于b。

注意c为0的情况。

#include<cstdio>
long long a,b,c;
int main() {
scanf("%lld%lld%lld",&a,&b,&c);
if(c==0&&b==a||c&&(b-a)%c==0&&(b-a)/c>=0)puts("YES");
else puts("NO");
return 0;
}

B - Modular Inverse

ZOJ - 3609 

求逆元。以前写过题解,http://www.cnblogs.com/flipped/p/5193777.html

C - Prison rearrangement

POJ - 1636

两个监狱各有m个犯人,现在各拿出相同个犯人交换,给定两个监狱有那些犯人是不能在一个监狱的,求最多交换多少人,且不超过m/2。

先用dfs计算出二分图的联通子图的左边的个数和右边的个数,然后用动态规划:

\(dp[i][j]\)表示左边共选了i个人,右边j个人交换是否可行。

\(dp[i][j]|=dp[i-le[i]][j-re[i]]\)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#define ll long long
#define N 305
using namespace std;
int s,m,r,g[N][N];
int cnt,le[N],re[N];
int dp[N][N];
bool vis[2][N];
void dfs(int v,int c){
vis[c][v]=1;
if(c)le[cnt]++;else re[cnt]++;//连通图左边、右边的点个数
for(int i=1;i<=m;i++)//c==1,左边走到右边
if((c&&g[v][i]||!c&&g[i][v])&&!vis[!c][i]) dfs(i,!c);
}
int main() {
scanf("%d",&s);
for(int cas=1;cas<=s;cas++){
for(int i=0;i<N;i++)le[i]=re[i]=vis[0][i]=vis[1][i]=0;
memset(g,0,sizeof g);
memset(dp,0,sizeof dp);
cnt=0;
scanf("%d%d",&m,&r);
for(int i=1;i<=r;i++){
int x,y;
scanf("%d%d",&x,&y);
g[x][y]=1;
}
for(int i=1;i<=m;i++)
for(int c=0;c<2;c++)
if(!vis[c][i]){
cnt++;
dfs(i,c);
}
dp[0][0]=1;
for(int i=1;i<=cnt;i++)
for(int j=m/2;j>=le[i];j--)
for(int k=m/2;k>=re[i];k--)
dp[j][k]|=dp[j-le[i]][k-re[i]]; int i=m/2;
while(i&&dp[i][i]==0)i--;
printf("%d\n",i);
}
return 0;
}

D - Task Schedule

HDU - 3572

n个任务,m个机器,每台机器每天只能做一个任务,每个任务允许时间范围\([s_i,e_i]\),需要时间长度\(p_i\)。求能否安排所有任务使得它们都能完成。

网络流最大流:

构图:1. 源点s->任务,容量p。2. 日子->汇点t,容量m。3. 任务->允许范围的日子,容量1。

用isap可以直接过,dinic我超时了,当前弧优化后就过了。

优化后的dinic:

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
#define N 1005
#define M 2000005
#define INF 0x7fffffff
struct edge{
int to,next,w;
}e[M];
int head[N],g[N],cnt;
int d[N],ans,tans;
int st,ed;
void add(int u,int v,int w){
e[cnt]=(edge){v,head[u],w};head[u]=cnt++;
e[cnt]=(edge){u,head[v],0};head[v]=cnt++;//反向弧
}
int bfs(){
memset(d,-1,sizeof d);
queue<int>q;
q.push(st);
d[st]=0;
while(!q.empty()){
int i,k=q.front();
q.pop();
for(i=head[k];~i;i=e[i].next){
int v=e[i].to;
if(e[i].w>0&&d[v]==-1){
d[v]=d[k]+1;
q.push(v);
}
}
}
return d[ed]>0;
}
int dinic(int k,int low){//在k节点有流量low,到终点ed的最大流
if(k==ed||low==0)return low;
int a,res=0;
for(int &i=g[k];~i;i=e[i].next){//这个g就是当前弧优化
int v=e[i].to;
if(d[v]==d[k]+1&&e[i].w>0&&(a=dinic(v,min(low,e[i].w)))){
res+=a;//当前这条弧送了a流量到终点
low-=a;
e[i].w-=a;
e[i^1].w+=a;
if(!low) break;//如果k相连的前面几条弧已经把low那么多流量送到终点,就不需要后面的弧了,下次访问k时就从现在的g[k]这条弧开始增广。
}
}
return res;
}
void solve(){
ans = 0;
while(bfs()) {
memcpy(g,head,sizeof g);//重新计算过层次图后再初始化当前弧g
while(tans=dinic(st, INF)) ans += tans;
}
}
void init(){
cnt=0;
memset(head, -1, sizeof head);
}
int p[N],s[N],ee[N];
int main(){
int t;
scanf("%d",&t);
for(int cas=1;cas<=t;cas++){
printf("Case %d: ",cas);
int n,m;
int pans=0;
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&p[i],&s[i],&ee[i]);
add(st,i,p[i]);
pans+=p[i];
for(int j=s[i];j<=ee[i];j++)
add(i,j+n,1);
}
ed=n+501;
for(int i=n+1;i<=n+500;i++){
add(i,ed,m);
}
solve();
if(ans==pans)puts("Yes\n");
else puts("No\n");
}
}

E - Sasha and Array

CodeForces - 718C 

给定n(\(1\le n\le 10^5\))个数\(a_i\),和m(\(1\le m\le 10^5\))个操作:

1 l r x :代表[l,r]区间的a都增加x

2 l r:代表求\(\sum_{i=l}^{i=r} fib(a_i)\), fib(i) 为第 i 项Fibonacci (斐波那契)数

对于操作2,输出答案,且对\(10^9+7\)取模。

题解1:

求 fibonacci 时是用矩阵快速幂(矩阵不一定像这样):

\[\left[\begin{matrix}
fib(n-1) & fib(n)\\
fib(n) & fib(n+1)
\end{matrix}\right]=
\left[\begin{matrix}
fib(n-2) &fib(n-1) \\
fib(n-1) & fib(n)
\end{matrix}\right]
*
\left[\begin{matrix}
0 & 1 \\
1 & 1
\end{matrix}\right]
\]

也就是

\[\left[\begin{matrix}
fib(n-1) & fib(n)\\
fib(n) & fib(n+1)
\end{matrix}\right]=
\left[\begin{matrix}
0 & 1 \\
1 & 1
\end{matrix}\right]^{n-1}
\]

于是可以用线段树每个节点是矩阵,线段树维护矩阵的和,就可以得到通项和。

我需要注意的是:

  • 用long long,否则会爆
  • 懒惰标记用法
  • 提前算好bv(b矩阵的x次方)
  • query不要忘记取模
  • 矩阵里的加和乘直接写,而不用for的话,可以-1s。

题解2:

考虑斐波那契数列的通项:

\[f[n]=\frac{(\frac{1+\sqrt 5}{2})^n-(\frac{1-\sqrt 5}{2})^n}{\sqrt 5}
\]

用两个线段树维护两个复数 $a\pm b\sqrt 5 $ 的n次幂的区间和:

  1. 增加x,则该区间对应的两个次幂分别乘上x次幂。
  2. 区间求和,即该区间对应的两个次幂相减后的b。因为答案一定是整数,所以相减再除以\(\sqrt 5\) 后,整数部分就是b。

除以2用乘以inv2 ( 2关于MOD的乘法逆元)来表示。这两个复数就是\((inv2,inv2),(inv2,-inv2)\)。

代码1:

#include<cstdio>
#include<cstring>
#define ll long long
#define N 100005
const ll M = 1e9+7;
using namespace std;
struct Mat{
ll a[2][2];
Mat operator + (const Mat &B){
Mat C;
C.a[0][0]=(a[0][0]+B.a[0][0])%M;
C.a[0][1]=(a[0][1]+B.a[0][1])%M;
C.a[1][0]=(a[1][0]+B.a[1][0])%M;
C.a[1][1]=(a[1][1]+B.a[1][1])%M;
return C;
}
Mat operator * (const Mat &B){
Mat C;
C.a[0][0]=(a[0][0]*B.a[0][0]+a[0][1]*B.a[1][0])%M;
C.a[0][1]=(a[0][0]*B.a[1][0]+a[0][1]*B.a[1][1])%M;
C.a[1][0]=(a[1][0]*B.a[0][0]+a[1][1]*B.a[1][0])%M;
C.a[1][1]=(a[1][0]*B.a[1][0]+a[1][1]*B.a[1][1])%M;
return C;
}
}e={1,0,0,1},b={0,1,1,1},bv,tr[N<<2],lz[N<<2];
Mat pow (int t){
Mat C=e,A=b;
while(t){
if(t&1)C=C*A;
A=A*A;
t>>=1;
}
return C;
}
int L[N<<2],R[N<<2];
void pushDown(int x){
tr[x<<1] =tr[x<<1] *lz[x];
tr[x<<1|1]=tr[x<<1|1]*lz[x];
lz[x<<1] =lz[x<<1] *lz[x];
lz[x<<1|1]=lz[x<<1|1]*lz[x];
lz[x]=e;
}
void pushUp(int x){
tr[x]=tr[x<<1]+tr[x<<1|1];
}
void build(int l,int r,int x){
L[x]=l;R[x]=r;
lz[x]=e;
if(l==r){
int a;
scanf("%d",&a);
tr[x]=pow(a-1);
return;
}
int m=l+r>>1;
build(l,m,x<<1);
build(m+1,r,x<<1|1);
pushUp(x);
}
void add(int l,int r,int x,int v){
if(l<=L[x]&&r>=R[x]){
tr[x]=tr[x]*bv;
lz[x]=lz[x]*bv;
return;
}
if(L[x]!=R[x])pushDown(x);
if(l<=R[x<<1])add(l,r,x<<1,v);
if(r>R[x<<1])add(l,r,x<<1|1,v);
pushUp(x);
}
ll query(int l,int r,int x){
if(l>R[x]||r<L[x])return 0;
if(l<=L[x]&&r>=R[x])return tr[x].a[1][1];
if(L[x]!=R[x])pushDown(x);
return (query(l,r,x<<1)+query(l,r,x<<1|1))%M;
}
int main() {
int n,m,l,r,x,op;
scanf("%d %d",&n,&m);
build(1,n,1);
for(int i=1;i<=m;i++){
scanf("%d %d %d",&op, &l, &r);
if(op==1) scanf("%d",&x), bv=pow(x), add(l,r,1,x);
else printf("%lld\n",query(l,r,1));
}
return 0;
}

代码2:

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
const int N=1e5+5;
const ll M=1e9+7;
const ll inv2=5e8+4;
using namespace std; struct Num{
ll a,b;
Num():a(1),b(0){}
Num(ll x,ll y):a(x%M),b(y%M){}
Num operator +(const Num &B)const{
return Num(a+B.a,b+B.b);
}
Num operator *(const Num &B)const{
return Num(a*B.a+b*B.b*5,a*B.b+b*B.a);
}
Num operator ^(int t)const{
Num A=(*this),B(1,0);
while(t){if(t&1)B=B*A;A=A*A;t>>=1;}
return B;
}
}eA(inv2,inv2),eB(inv2,-inv2),tr[2][N<<2],lz[2][N<<2]; void pushup(int i,int x){
tr[i][x]=tr[i][x<<1]+tr[i][x<<1|1];
}
void pushdown(int i,int x){
tr[i][x<<1]=tr[i][x<<1]*lz[i][x];
tr[i][x<<1|1]=tr[i][x<<1|1]*lz[i][x];
lz[i][x<<1]=lz[i][x<<1]*lz[i][x];
lz[i][x<<1|1]=lz[i][x<<1|1]*lz[i][x];
lz[i][x].a=1,lz[i][x].b=0;
} #define ls l,r,L,L+R>>1,x<<1
#define rs l,r,(L+R>>1)+1,R,x<<1|1 void add(int l,int r,int L,int R,int x,int i,Num ad){
if(l>R||L>r)return;
if(l<=L&&R<=r){
tr[i][x]=tr[i][x]*ad;
lz[i][x]=lz[i][x]*ad;
return;
}
if(L!=R) pushdown(i,x);
add(ls,i,ad);add(rs,i,ad);
pushup(i,x);
}
ll query(int l,int r,int L,int R,int x){
if(l>R||L>r)return 0;
if(l<=L&&R<=r)return (tr[0][x].b-tr[1][x].b)%M;
if(L!=R)pushdown(0,x),pushdown(1,x);
return (query(ls)+query(rs))%M;
} int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1,a;i<=n;i++){
scanf("%d",&a);
add(i,i,1,n,1,0,eA^a);
add(i,i,1,n,1,1,eB^a);
}
for(int i=1,t,l,r,x;i<=m;i++){
scanf("%d%d%d",&t,&l,&r);
if(t==1){
scanf("%d",&x);
add(l,r,1,n,1,0,eA^x);
add(l,r,1,n,1,1,eB^x);
}
else printf("%lld\n",query(l,r,1,n,1));
}
return 0;
}

F - Lena and Queries

CodeForces - 678F 

3种操作:

1 a b :添加一对数到集合里。

2 i :移除第 i 次操作添加的一对数。

3 q : 询问\(q\cdot x+y\)最大值,(x,y)是当前在集合里的。

给出n(\(1\le n\le 3\cdot 10^5\))次操作,对于3操作输出最大值。

题解:

对于每对数,相当于平面坐标的一个点。它出现的操作区间是[L,R],L是添加它的操作编号,如果有移除,则R是移除时的操作下标,否则R是n。

全部操作读入后,将点插入所在操作区间的线段树节点。

求\(z=q\cdot x+y\)的最大值,相当于过点(x,y)且斜率为-q的直线\(y=-q\cdot x +z\)的y轴截距最大,则(x,y)一定是凸包上点。用单调栈求凸包,再三分求最大值。

从底向上用线段树维护操作区间里的点形成的凸壳,同时,对在当前区间里的所有3操作,用三分求得在当前区间的凸包点集下,qx+y的最大值,更新一下答案。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#define ll long long
#define N 300005
const ll INF = 1LL << 61;
using namespace std; int t[N],r[N],empty[N];
ll ans[N];
struct Point{
ll x,y;
bool operator <(const Point &B)const{
return x<B.x||(x==B.x&&y<B.y);
}
Point operator -(const Point &B)const{
return (Point){x-B.x,y-B.y};
}
Point operator +(const Point &B)const{
return (Point){x+B.x,y+B.y};
}
ll operator ^(const Point &B)const{
return x*B.y-y*B.x;
}
ll operator *(const Point &B)const{
return x*B.x+y*B.y;
}
}p[N],S[N]; vector<Point> tr[N<<2];
void insert(int l,int r,int L,int R,int o,int v){
if(l<=L&&R<=r){
tr[o].push_back(p[v]);
return;
}
int M=L+R>>1;
if(l<=M)insert(l,r,L,M,o<<1,v);
if(r>M)insert(l,r,M+1,R,o<<1|1,v);
}
void query(int x,int n){
int l=1,r=n;
while(r-l>=3){//三分求最大值
int m1=l+(r-l)/3;
int m2=l+(r-l)*2/3;
if(p[x]*S[m1]<p[x]*S[m2])l=m1;
else r=m2;
}
for(int i=l;i<=r;i++)
ans[x]=max(ans[x],p[x]*S[i]);
} void solve(int l,int r,int o){
if(l<r){
int m=l+r>>1;
solve(l,m,o<<1);
solve(m+1,r,o<<1|1);
}
sort(tr[o].begin(),tr[o].end());
int top=0;
for(int i=0;i<tr[o].size();i++){
while(top>1&&((S[top]-S[top-1])^(tr[o][i]-S[top]))>=0)top--;
S[++top]=tr[o][i];
}
for(int i=l;i<=r;i++) if(t[i]==3&&!empty[i]) query(i,top);
} int main() {
int n;
scanf("%d",&n);
for(int i=1,cnt=0,x;i<=n;i++){
scanf("%d",&t[i]);
if(t[i]==1)
scanf("%lld %lld",&p[i].x,&p[i].y), r[i]=n, cnt++;
else if(t[i]==2)
scanf("%d",&x), r[x]=i, cnt--;
else
scanf("%lld",&p[i].x), p[i].y=1LL, empty[i]=(cnt==0), ans[i]=-INF;
} for(int i=1;i<=n;i++)if(t[i]==1&&i+1<=r[i]) insert(i,r[i],1,n,1,i); solve(1,n,1); for(int i=1;i<=n;i++)if(t[i]==3){
if(empty[i]) puts("EMPTY SET");
else printf("%lld\n",ans[i]);
}
return 0;
}

G - Pouring Rain

CodeForces - 667A 

下雨使水上升的速度:\(e\ cm/s\)

喝水使水减少的速度:\(v\ cm^3/s\)

杯子的直径:\(d\ cm\)

杯子里水的初始高度:\(h\ cm\)

求若能喝完水,需要多少秒。

#include<cstdio>
#include<cmath>
#define pi acos(-1.0)
using namespace std;
double d,h,v,e;
int main() {
scanf("%lf%lf%lf%lf",&d,&h,&v,&e);
double s=v/pi/(d/2)/(d/2)-e;
if(s>0)printf("YES\n%f",h/s);
else puts("NO");
return 0;
}

H - Constellation

CodeForces - 618C

给定n个点,求可组成一个三角形且内部没有其它点的三个点。

将点按x,再按y排序。选取第一第二个点,再输出不和它们构成直线的第一个点。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define ll long long
#define N 100005
using namespace std;
struct star{
ll x,y;int id;
}s[N];
int n;
int cmp(star a,star b){
return a.x<b.x||a.x==b.x&&a.y<b.y;
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld%lld",&s[i].x,&s[i].y);
s[i].id=i;
}
sort(s+1,s+1+n,cmp);
printf("%d %d ",s[1].id,s[2].id);
for(int i=3;i<=n;i++){
if((s[1].x-s[2].x)*(s[2].y-s[i].y)!=(s[1].y-s[2].y)*(s[2].x-s[i].x)){
printf("%d",s[i].id);break;
}
}
return 0;
}

BUPT2017 wintertraining(15) #1 题解的更多相关文章

  1. BUPT2017 wintertraining(15) #3 题解

    我觉得好多套路我都不会ヘ(;´Д`ヘ) 题解拖到情人节后一天才完成,还有三场没补完,真想打死自己.( ˙-˙ ) A - 温泉旅店 UESTC - 878  题意 ​ 有n张牌,两人都可以从中拿出任意 ...

  2. BUPT2017 wintertraining(15) #2 题解

    这场有点难,QAQ.补了好久(。• ︿•̀。) ,总算能写题解了(つд⊂) A. Beautiful numbers CodeForces - 55D 题意 ​ 求\([l,r](1\le l_i\l ...

  3. BUPT2017 wintertraining(15) #9

    下面不再说明题意了请自行读题,直接放contest链接. https://vjudge.net/contest/151607 A.考虑当火车隔k站一停时 区间长度 >= k 的纪念品一定能买到 ...

  4. BUPT2017 springtraining(15) #3

    这里这里 A.签到题 #include <cstdio> double a[] = {0.4, 0.16, 0.063, 0.025, 0.010, 0.004}; int main() ...

  5. BUPT2017 wintertraining(16) #9

    龟速补题.目前基本弃坑.已暂时放弃 D.I 两题. 下面不再写题意了直接说解法注意事项之类,直接放contest链接. https://vjudge.net/contest/151537 A.The ...

  6. BUPT2017 springtraining(16) #1 题解

    https://vjudge.net/contest/162590 A: 不难发现,当L=R时输出L,当L<R时输出2. B: 贪心得配对.1和n配 2和n-1配,对与对直接只要花1个代价就可以 ...

  7. 【AtCoder - 2300】Snuke Line(树状数组)

    BUPT2017 wintertraining(15) #9A 题意 有n个纪念品,购买区间是\([l_i,r_i]\).求每i(1-m)站停一次,可以买到多少纪念品. 题解 每隔d站停一次的列车,一 ...

  8. 【HDU - 4349】Xiao Ming's Hope

    BUPT2017 wintertraining(15) #8H 题意 求组合数C(n,i),i从0到n,里面有几个奇数. 题解 直接打表的话可能就直接发现规律了. 规律是n的二进制里有几个1,答案就是 ...

  9. 【HDU - 4348】To the moon(主席树在线区间更新)

    BUPT2017 wintertraining(15) #8G 题意 给一个数组a,有n个数,m次操作.\(N, M ≤ 10^5, |A i| ≤ 10^9, 1 ≤ l ≤ r ≤ N, |d| ...

随机推荐

  1. linux配置iptables(3)

    简单通用 web 服务器iptables 配置 *filter :INPUT DROP [0:0]:FORWARD DROP [0:0]:OUTPUT ACCEPT [0:0] #超出 链规则 的数据 ...

  2. es5中for...in 和es6中 for..of遍历

    //定义一个数组 var arr=['A','B','C']; //定义一个对象 var obj={name:'张三',age:20} // for..in 遍历数组 得到索引 for(var x i ...

  3. 轻量级WebApi请求插件:PostMan

    时间很宝贵,废话不多说,只说三句,如下: 十年河东,十年河西,莫欺骚年穷!~_~ 打错个字,应该是莫欺少年穷! 学历代表你的过去,能力代表你的现在,学习代表你的将来. 学无止境,精益求精. 本次介绍的 ...

  4. .net core实践系列之短信服务-为什么选择.net core(开篇)

    前言 从今天我将会写.net core实战系列,以我最近完成的短信服务作为例子.该系列将会尽量以最短的时间全部发布出来.源码也将优先开源出来给大家. 源码地址:https://github.com/S ...

  5. Linux下绑定网卡的操作记录

    公司采购的服务器安装了双网卡,并进行bond网卡绑定设置,网卡绑定mode共有七种(0~6) bond0.bond1.bond2.bond3.bond4.bond5.bond6. 第一种模式:mod= ...

  6. AnyProxy做App网络流量测试

    前言: AnyProxy是一个开放式的HTTP代理服务器.Github主页:[https://github.com/alibaba/anyproxy]主要特性包括: 基于Node.js,开放二次开发能 ...

  7. 牛客训练赛25-A-因数个数

    题目链接https://www.nowcoder.com/acm/contest/158/A 无语...这题很迷啊,原谅我的菜,刚开始想用预处理欧拉筛和前缀和,可是这题太血崩了,这样一样要遍历,1-e ...

  8. easyUI中textbox或number的数值大小校验

    例:textbox里面,要求做两个textbox名字为(A,B),其中两个的数字大小范围是-10~10之间,之后其中A的值必须大于B所填的数字,如果输入错误,则提示出弹出框,并清空数据. <!D ...

  9. 《移山之道》Reading Task

    老师布置的阅读任务虽然是附加的作业,但是对我来说是个很好的学习机会.软件工程主要是对工程的开发进行学习,毕竟在学校老师教了那么多的知识,我们课下做了那么多的练习并没有提高我们做一个工程的能力.一个项目 ...

  10. 个人阅读作业 final

    前两次阅读作业链接: http://www.cnblogs.com/SteelPillar/p/4027877.html http://www.cnblogs.com/SteelPillar/p/40 ...