前言
今天做得不错吧,……
比赛题目
JZOJ 1619 音乐节拍
题目大意:
n个节拍,对于第i个节拍,持续的时间是Bi−1至Bi−1B_{i-1}至B_i-1Bi−1至Bi−1,q个询问,求在某个时间是第几个节拍。
分析
思路1:(在线)时间复杂度:O(n+qlogn)O(n+qlogn)O(n+qlogn)
由于持续的时间是递增的(前缀和),所以用二分查找找出答案
思路2:(离线)时间复杂度:O(qlogq+q)O(qlogq+q)O(qlogq+q)
把询问的时间从小到大排序,运用前缀和找出答案。
代码(离线)
#include <cstdio>
#include <cctype>
#include <algorithm>
#define us unsigned short
using namespace std;
struct rec{int x; us y;}b[50001]; us n,q,t=1,a[50001],ans[50001]; int tosic=-1;
int in(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
bool cmp(rec x,rec y){return x.x<y.x;}
int main(){
freopen("mnotes.in","r",stdin);
freopen("mnotes.out","w",stdout);
n=in(); q=in();
for (int i=1;i<=n;i++) a[i]=in();
for (int i=1;i<=q;i++) b[i]=(rec){in(),i};
stable_sort(b+1,b+1+q,cmp);
for (int i=1;i<=n;i++){
tosic+=a[i];
while (b[t].x<=tosic&&t<=q) ans[b[t++].y]=i;
}
for (int i=1;i<=q;i++) printf("%d\n",ans[i]);
return 0;
}
代码(在线)
#include <cstdio>
#include <cctype>
using namespace std;
int n,q,a[50005];
int in(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
int main(){
freopen("mnotes.in","r",stdin);
freopen("mnotes.out","w",stdout);
n=in(); q=in(); int x;
for (int i=1;i<=n;i++) x=in(),a[i+1]=a[i]+x;
while (q--){
x=in();
int l=1,r=n+1;
while (l<=r){
int mid=(l+r)>>1;
if (x>=a[mid]) l=mid+1; else r=mid-1;
}
printf("%d\n",r);
}
return 0;
}
JZOJ 1620 电视游戏问题
题目大意
n个平台,每个平台上的游戏只能在该平台上运行,游戏和平台都要花费钱,游戏还可以有产出值,求在限定的钱内的最大产出值。
分析
01背包,状态转移方程f[j]=max(f[j],f[j−w[i]]+c[i])f[j]=max(f[j],f[j-w[i]]+c[i])f[j]=max(f[j],f[j−w[i]]+c[i])
但是这是对于单个平台的最大产出值,所以再用一个dp[j]表示所有平台的最大产出值,
开始f[j]=dp[j−x](减去平台的费用x)f[j]=dp[j-x](减去平台的费用x)f[j]=dp[j−x](减去平台的费用x),最后dp[j]=max(dp[j],f[j])(求最大值)dp[j]=max(dp[j],f[j])(求最大值)dp[j]=max(dp[j],f[j])(求最大值)……
代码
#include <cstdio>
#include <cctype>
using namespace std;
int dp[100001],f[100001],n,m,x,num,w,c;
int in(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
int max(int a,int b){return (a>b)?a:b;}
int main(){
freopen("vidgame.in","r",stdin);
freopen("vidgame.out","w",stdout);
n=in(); m=in();
for (int i=1;i<=n;i++){
x=in(); num=in();
for (int j=x;j<=m;j++) f[j]=dp[j-x];//购买平台
for (int j=1;j<=num;j++){
w=in(); c=in();
for (int k=m-w;k>=x;k--)
f[k+w]=max(f[k+w],f[k]+c);//01背包
}
for (int j=x;j<=m;j++) dp[j]=max(dp[j],f[j]);//计算最大值
}
return !printf("%d",dp[m]);
}
JZOJ 1621 头晕的奶牛
题目大意:
在一个图中:给出有向边和无向边,且有向边不能改变,把无向边的方向固定,使图变成有向无环图
并输出改变方向的无向边。
分析
可以用拓扑排序,求出点的顺序,当无向边的方向满足顺序则成立
证明:当按拓扑排序后顺序小的连向大的不会有环
那怎么样求拓扑排序,当某点的入点为0加入队列,否则当通过有向边找到一个点将其入度-1重复进行,进入队列的顺序就是答案。
PS:程序里out数组改为in数组
代码
#include <cstdio>
#include <cctype>
#define N 100001
#include <queue>
using namespace std;
int n,m1,m2,x,y1,out[N],y[N],now,next[N],ls[N],top[N]; queue<int>q;
int in(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
int main(){
freopen("dizzy.in","r",stdin);
freopen("dizzy.out","w",stdout);
n=in(); m1=in(); m2=in();
for (int i=1;i<=m1;i++){
x=in();y[i]=in(); out[y[i]]++;//入点
next[i]=ls[x]; ls[x]=i;
}
for (int i=1;i<=n;i++) if (!out[i]&&ls[i]) q.push(i);//当连接有向边而且没有入点
while (q.size()){//拓扑排序
x=q.front();q.pop(); top[x]=++now;
for (int i=ls[x];i;i=next[i])
if (out[y[i]]>1) out[y[i]]--;
else q.push(y[i]);
}
for (int i=1;i<=m2;i++){
x=in(); y1=in();
if (top[x]<top[y1]) printf("%d %d\n",x,y1); else printf("%d %d\n",y1,x);
}
return 0;
}
JZOJ 1622 过路费
题目大意:
询问两点间的路费(路径的边权和+路径中最大的点权)
分析
floyd求多源最短路径,对于最大点权,点权排序,最大点权必然是(i,j,k(中间点))的最大值
代码
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
struct rec{int x,y;}c[251]; int d[251];
int n,m,q,cost[251][251],tost[251][251];
int in(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
bool cmp(rec a,rec b){return a.x<b.x;}
int min(int a,int b){return (a<b)?a:b;}
int tmax(int a,int b,int c){return (a<b)?((b<c)?c:b):((a<c)?c:a);}
int main(){
freopen("toll.in","r",stdin);
freopen("toll.out","w",stdout);
memset(cost,0x3f,sizeof(cost));
memset(tost,0x3f,sizeof(tost));
n=in(); m=in(); q=in();
for (int i=1;i<=n;i++) c[i]=(rec){in(),i};
stable_sort(c+1,c+1+n,cmp);//排序
for (int i=1;i<=n;i++) d[c[i].y]=i;//记录原来的点的当前位置
while (m--){
int x=in(); int y=in(); int w=in();
cost[d[x]][d[y]]=cost[d[y]][d[x]]=min(w,cost[d[y]][d[x]]);//有多条道路
}
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
cost[i][j]=min(cost[i][j],cost[i][k]+cost[k][j]),
tost[i][j]=min(tost[i][j],cost[i][j]+tmax(c[i].x,c[j].x,c[k].x));//floyd
while (q--){int x=in(); int y=in(); printf("%d\n",tost[d[x]][d[y]]);}
return 0;
}
后续
PS:四道题目分别在洛谷的2969 2967 2017 2966