2018.7.3模拟赛
考炸了考炸了。。
T1超级大水题,结果二分写挂???70分走人。。呜呜。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int MAXN = 100005;
inline int rd(){
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<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
int n,ans=0;
struct Time{
int st,ed;
}t[MAXN];
inline bool cmp(Time a,Time b){
return a.ed<b.ed;
}
inline bool check(int x){
int k=x;
for(register int i=1;i<=n;i++){
k+=t[i].st;
if(k>t[i].ed) return false;
}
return true;
}
int main(){
// freopen("manage.in","r",stdin);
// freopen("manage.out","w",stdout);
n=rd();
for(register int i=1;i<=n;i++)
t[i].st=rd(),t[i].ed=rd();
sort(t+1,t+1+n,cmp);
int l=0,r=t[1].ed-t[1].st;
// for(register int i=1;i<=n;i++) cout<<t[i].st<<" "<<t[i].ed<<endl;
if(r<0) {puts("-1");return 0;}
while(l<=r){
int mid=(l+r)>>1;
// cout<<l<<" "<<r<<" ";
// cout<<mid<<endl;
if(check(mid)) {l=mid+1;ans=mid;}
else r=mid-1;
}
if(ans==0 && !check(0)) puts("-1");
else printf("%d",ans);
return 0;
}
/*
4
3 5
8 14
5 20
1 16
*/
/*
3
1 100
100 105
110 300
*/
T2 tarjan + 树上背包,结果tanjan边连成双向,60分滚蛋。我真的是菜的抠脚。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int MAXN = 505;
inline int rd(){
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<<1)+(x<<3)+ch-48;ch=getchar();}
return x*f;
}
int n,m,w[MAXN],val[MAXN],W[MAXN],V[MAXN];
int head[MAXN],cnt;
int dfn[MAXN],low[MAXN],xx[MAXN],head_[MAXN],cnt_;
int sta[MAXN],top,num;
int col[MAXN],col_num,du[MAXN];
int dp[MAXN][MAXN],ans;
bool vis[MAXN];
//dp[x][i] 表示以x为节点的子树,用了i的空间,最大权值
struct Edge{
int nxt,to;
}edge[MAXN<<1],edge_[MAXN<<1];
inline void add(int bg,int ed){
edge[++cnt].to=ed;
edge[cnt].nxt=head[bg];
head[bg]=cnt;
}
inline void add_(int bg,int ed){
edge_[++cnt_].to=ed;
edge_[cnt_].nxt=head_[bg];
head_[bg]=cnt_;
}
inline void tarjan(int x){
dfn[x]=low[x]=++num;
vis[x]=1;
sta[++top]=x;
for(register int i=head[x];i;i=edge[i].nxt){
int u=edge[i].to;
if(!dfn[u]){
tarjan(u);
low[x]=min(low[x],low[u]);
}
else if(vis[u])
low[x]=min(low[x],dfn[u]);
}
if(low[x]==dfn[x]){
vis[x]=0;
col_num++;
while(sta[top]!=x){
col[sta[top]]=col_num;
vis[sta[top]]=0;
top--;
}
top--;
col[x]=col_num;
}
}
inline void dfs(int x){
for(register int i=W[x];i<=m;i++) dp[x][i]=V[x];
for(register int i=head_[x];i;i=edge_[i].nxt){
int u=edge_[i].to;
dfs(u);
for(register int j=m;j>=W[x];j--)
for(register int k=0;k<=j-W[x];k++){
dp[x][j]=max(dp[x][j],dp[u][k]+dp[x][j-k]);
}
}
}
int main(){
// freopen("software.in","r",stdin);
// freopen("software.out","w",stdout);
n=rd();m=rd();
for(register int i=1;i<=n;i++) w[i]=rd();
for(register int i=1;i<=n;i++) val[i]=rd();
for(register int i=1;i<=n;i++){
xx[i]=rd();
add(xx[i],i);
}
for(register int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
// for(register int i=0;i<=n;i++) cout<<col[i]<<" ";cout<<endl;
col[0]=0;
for(register int i=1;i<=n;i++){
W[col[i]]+=w[i];
V[col[i]]+=val[i];
if(col[i]==col[xx[i]]) continue;
add_(col[xx[i]],col[i]);
du[col[i]]++;
// if(col[xx[i]]==col[0]) mark[col[i]]=1;
}
for(register int i=1;i<=col_num;i++)
if(!du[i]) add_(col[0],i);
// for(register int i=1;i<=col_num;i++) {
// if(i!=col[0])
// add(i,col[0]);
// }
// for(register int i=1;i<=col_num;i++) cout<<W[i]<<" "<<V[i]<<endl;
dfs(0);
// for(register int i=0;i<=col_num;i++)
// for(register int j=0;j<=m;j++)
// cout<<i<<" "<<j<<" "<<dp[i][j]<<endl;
ans=dp[0][m];
printf("%d",ans);
return 0;
}
/*
3 10
5 5 6
2 3 4
0 1 1
*/
/*
5 7
4 2 1 2 3
5 3 50 6 19
0 1 2 2 1
*/
/*
7 14
5 1 6 6 6 1 1
1 2 1 2 1 5 4
0 1 2 2 1 5 5
*/
/*
7 23
4 4 4 4 1 4 4
100 100 100 100 1 5 4
4 1 2 3 0 5 5
*/
T3 不太会,打了个暴力+优化,极限卡过70。(传说中的n^2过100000?)
正解是线段树,没往这上面像。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = 400005;
inline int rd(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-48;ch=getchar();}
return x*f;
}
int n,m,cnt[MAXN];
double mx[MAXN];
inline int count(int l,int r,int x,double k){
if(l==r) return mx[x]>k;
int mid=(l+r)>>1;
if(mx[x<<1]<=k) return count(mid+1,r,x<<1|1,k);
else return cnt[x]-cnt[x<<1]+count(l,mid,x<<1,k);
//注意cnt[x]-cnt[x<<1]不能直接写成cnt[x<<1|1],因为cnt数组表示的只是
//每个区间的递增序列,与其他区间无关,所以左边可能挡住右边。
}
inline void change(int l,int r,int x,int q,double k){
if(l==r){
mx[x]=k;
cnt[x]=1;
return;
}
int mid=(l+r)>>1;
if(q<=mid) change(l,mid,x<<1,q,k);
else change(mid+1,r,x<<1|1,q,k);
mx[x]=mx[x<<1]>mx[x<<1|1]?mx[x<<1]:mx[x<<1|1];
cnt[x]=cnt[x<<1]+count(mid+1,r,x<<1|1,mx[x<<1]);
}
int main(){
n=rd();m=rd();
for(register int i=1;i<=m;i++){
int x=rd(),y=rd();
double k=(double)y/(double)x;
change(1,n,1,x,k);
printf("%d\n",cnt[1]);
}
}