LibreOJ刷题计划 &《信息学奥赛一本通》提高版题目
Posted yzx1798106406
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LibreOJ刷题计划 &《信息学奥赛一本通》提高版题目相关的知识,希望对你有一定的参考价值。
2019.1.27
#10082. 「一本通 3.3 例 1」Word Rings
题意
每组数据读入一个n和n个字符串。定义前2个与末尾2个字母相同可以连接。问使这个环串的平均长度最大。求这个最大值。不存在输出(No solution)。
思路
平均值公式:
[
Average=(E_1+E_2+.....+E_n)/n
]
[ Average*n=(E_1+E_2+...+E_n) ]
[ (E_1-Average)+(E_2-Average)+...+(E_n-Average)=0 ]
那么可以二分答案:
[
(E_1-Ans)+(E_2-Ans)+...+(E_n-Ans)geq0
]
然后瞎搞spfa。
#include<algorithm>
#include<bitset>
#include<complex>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<cmath>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#define E 200010
#define eps 1e-3
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
return res*f;
}
inline void write(int x){
if(x<0) putchar('-'),x=-x;
if(x<10) putchar(x+'0');
else{
write(x/10);
putchar(x%10+'0');
}
}
//queue<int> q;
//set<int> s;
//priority_queue<int> q1;
//priority_queue<int,vector<int>,greater<int> > q2;
//list<int> l;
//stack<int> s;
int n;
string str[100010];
int fir[E],nxt[E],son[E],tot,cnt,Max;
double w[E],dis[E],flag;
int vis[E];
int f[6666];
void add(int x,int y,double z){++tot;son[tot]=y;nxt[tot]=fir[x];fir[x]=tot;w[tot]=z;}
void spfa(int s,int v,double mid){
if(flag==1) return ;
vis[s]=v;
for(int i=fir[s];i;i=nxt[i]){
int to=son[i];
if(dis[s]+w[i]>dis[to]+mid){
dis[to]=dis[s]+w[i]-mid;
if(dis[to]>Max){
flag=1;
return ;
}
if(!vis[to]) spfa(to,v,mid);
if(flag) return ;
else if(vis[to]==v){
flag=1;
return ;
}
}
}
vis[s]=0;
}
bool check(double mid){
flag=0;
for(int i=0;i<=cnt;i++) dis[i]=0.0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=cnt;i++){
spfa(i,i,mid);
if(flag==1) break;
}
return flag;
}
int main(){
// freopen("code.in","r",stdin);freopen("code.out","w",stdout);
n=read();
while(n!=0){
for(int i=1;i<=n;i++) cin>>str[i];
memset(fir,0,sizeof(fir));
memset(f,0,sizeof(f));
tot=0;cnt=0;Max=0;
for(int i=1;i<=n;i++){
int len=str[i].length();
Max=max(Max,len);
int a=(str[i][0]-'a')*26+str[i][1]-'a';
int b=(str[i][len-2]-'a')*26+str[i][len-1]-'a';
if(!f[a]) f[a]=++cnt;
int A=f[a];
if(!f[b]) f[b]=++cnt;
int B=f[b];
add(A,B,(double)len);
}
Max*=n;
double l=0,r=1000,ans=-1,mid;
while(l+eps<r){
mid=(l+r)/2;
if(check(mid)) l=mid,ans=mid;
else r=mid;
}
if(ans!=-1) printf("%.2lf
",ans);
else puts("No solution");
n=read();
}
return 0;
}
#10083. 「一本通 3.3 例 2」双调路径
题意
读入一个图,计算最小路径的总数。费用时间都相同的两条最小路径只算一条,输出不同种类的最小路径数。
思路
设[f[i][j]]表示在i点且已花费j时的最少时间
[
f[i][j]=Min(f[k][i-Cost(k,i)]+Time(k,i)|For Each Edge(k,i))
]
#include<algorithm>
#include<bitset>
#include<complex>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<cmath>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#define E 5010
#define eps 1e-3
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
return res*f;
}
inline void write(int x){
if(x<0) putchar('-'),x=-x;
if(x<10) putchar(x+'0');
else{
write(x/10);
putchar(x%10+'0');
}
}
//queue<int> q;
//set<int> s;
//priority_queue<int> q1;
//priority_queue<int,vector<int>,greater<int> > q2;
//list<int> l;
//stack<int> s;
int n,m,s,e;
int fir[E],nxt[E],son[E],w[E],cost[E],tot;
void add(int x,int y,int z,int t){++tot;w[tot]=z;son[tot]=y;nxt[tot]=fir[x];cost[tot]=t;fir[x]=tot;}
int dp[105][10005][3],Max,ans,Min=2e9;
int vis[105][10005];
struct node{int pos,dis;};
queue<node> q;
node make(int x,int y){node pp;pp.pos=x;pp.dis=y;return pp;}
void spfa(){
while(!q.empty()) q.pop();
for(int i=1;i<=n;i++){
for(int j=0;j<=10005;j++){
dp[i][j][0]=2e9;
dp[i][j][1]=0;
}
}
dp[s][0][0]=0;
dp[s][0][1]=1;
vis[s][0]=1;
q.push(make(s,0));
while(!q.empty()){
int u=q.front().pos,dis=q.front().dis;q.pop();
vis[u][dis]=0;
for(int i=fir[u];i;i=nxt[i]){
int to=son[i];
if(dis+w[i]>Max+1) continue ;
if(dp[u][dis][0]+cost[i]<dp[to][dis+w[i]][0]){
dp[to][dis+w[i]][0]=dp[u][dis][0]+cost[i];
dp[to][dis+w[i]][1]=1;
if(vis[to][dis+w[i]]==0){
vis[to][dis+w[i]]=1;
q.push(make(to,dis+w[i]));
}
}
}
}
}
int main(){
// freopen("code.in","r",stdin);freopen("code.out","w",stdout);
n=read();m=read();s=read();e=read();
for(int i=1;i<=m;i++){
int x=read(),y=read(),z=read(),t=read();
add(x,y,z,t);
add(y,x,z,t);
}
Max=(n-1)*100+5;
spfa();
for(int i=0;i<=Max;i++){
if(!dp[e][i][1]) continue ;
if(dp[e][i][0]<Min){
ans++;
Min=dp[e][i][0];
}
}
write(ans);putchar('
');
return 0;
}
#10084. 「一本通 3.3 练习 1」最小圈
题意
读入一个有向图,求图中最小环的最小平均值时多少。
思路
当然食用二分+spfa啦。
基本思路同#10082. 「一本通 3.3 例 1」Word Rings
平均值公式:
[
Average=(E_1+E_2+.....+E_n)/n
]
[ Average*n=(E_1+E_2+...+E_n) ]
[ (E_1-Average)+(E_2-Average)+...+(E_n-Average)=0 ]
那么可以二分答案:
[
(E_1-Ans)+(E_2-Ans)+...+(E_n-Ans)geq0
]
然后瞎搞spfa。
但这次求最小值。
改一改符号就好了。
#include<algorithm>
#include<bitset>
#include<complex>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<cmath>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#define E 20010
#define eps 1e-10
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
return res*f;
}
inline void write(int x){
if(x<0) putchar('-'),x=-x;
if(x<10) putchar(x+'0');
else{
write(x/10);
putchar(x%10+'0');
}
}
//queue<int> q;
//set<int> s;
//priority_queue<int> q1;
//priority_queue<int,vector<int>,greater<int> > q2;
//list<int> l;
//stack<int> s;
int n,m;
int fir[E],nxt[E],son[E],tot;
double w[E],Max;
void add(int x,int y,double z){++tot;nxt[tot]=fir[x];son[tot]=y;fir[x]=tot;w[tot]=z;}
double dis[E],flag;
int vis[E];
int spfa(int s,double mid){
vis[s]=1;
for(int i=fir[s];i;i=nxt[i]){
int to=son[i];
if(dis[s]+w[i]-mid<dis[to]){
dis[to]=dis[s]+w[i]-mid;
if(vis[to]||spfa(to,mid)){vis[s]=0;return 1;}
}
}
vis[s]=0;
return 0;
}
bool check(double mid){
for(int i=0;i<=n;i++) dis[i]=0.0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++){
if(spfa(i,mid)==1) return 1;
}
return 0;
}
int main(){
n=read();m=read();
for(int i=1;i<=m;i++){
int x=read(),y=read();double z;
cin>>z;
add(x,y,(double)z);
}
double l=-1e7,r=1e7,mid,ans;
while(l+eps<r){
mid=(l+r)/2;
if(check(mid)) r=mid-eps,ans=mid;
else l=mid+eps;
}
printf("%.8lf
",ans);
return 0;
}
#10085. 「一本通 3.3 练习 2」虫洞 Wormholes
题意
现在 John 想借助这些虫洞来回到过去(在出发时刻之前回到出发点),请你告诉他能办到吗。 John 将向你提供 F 个农场的地图。
思路
当然食用spfa啦。
当然,因为我懒,所以将上一题代码改一改就好了呀。
注意建双向边。
注意建负边。
check时只需要传入参数0就好了。
因为又没有让你求平均值QWQ
#include<algorithm>
#include<bitset>
#include<complex>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<cmath>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#define E 20010
#define eps 1e-10
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
return res*f;
}
inline void write(int x){
if(x<0) putchar('-'),x=-x;
if(x<10) putchar(x+'0');
else{
write(x/10);
putchar(x%10+'0');
}
}
//queue<int> q;
//set<int> s;
//priority_queue<int> q1;
//priority_queue<int,vector<int>,greater<int> > q2;
//list<int> l;
//stack<int> s;
int n,m;
int fir[E],nxt[E],son[E],tot;
double w[E],Max;
void add(int x,int y,double z){++tot;nxt[tot]=fir[x];son[tot]=y;fir[x]=tot;w[tot]=z;}
double dis[E],flag;
int vis[E];
int spfa(int s,double mid){
vis[s]=1;
for(int i=fir[s];i;i=nxt[i]){
int to=son[i];
if(dis[s]+w[i]-mid<dis[to]){
dis[to]=dis[s]+w[i]-mid;
if(vis[to]||spfa(to,mid)){vis[s]=0;return 1;}
}
}
vis[s]=0;
return 0;
}
bool check(double mid){
for(int i=0;i<=n;i++) dis[i]=0.0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++){
if(spfa(i,mid)==1) return 1;
}
return 0;
}
int main(){
int T,W;
T=read();
while(T--){
n=read();m=read();W=read();
tot=0;
memset(fir,0,sizeof(fir));
for(int i=1;i<=m;i++){
int x=read(),y=read();double z;
cin>>z;
add(x,y,(double)z);
add(y,x,(double)z);
}
for(int i=1;i<=W;i++){
int x=read(),y=read();double z;
cin>>z;
add(x,y,-z);
}
if(check(0)) puts("YES");
else puts("NO");
}
return 0;
}
#10086. 「一本通 3.3 练习 3」Easy SSSP
题意
给你一个图,问从源点到每个节点的最短路径分别是多少。
如果存在负权回路,只输出一行 -1;如果不存在负权回路,再求出一个点 S 到每个点的最短路的长度。如果 S 与这个点不连通,则输出 NoPath
。
思路
当然食用spfa啦。
先跑一下非源点的。万一数据卡你其他有环呢?
然后再跑一次源点。得出Ans
#include<algorithm>
#include<bitset>
#include<complex>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<cmath>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#define E 2000010
#define eps 1e-10
#define ll long long
using namespace std;
inline ll read(){
ll res=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
return res*f;
}
inline void write(ll x){
if(x<0) putchar('-'),x=-x;
if(x<10) putchar(x+'0');
else{
write(x/10);
putchar(x%10+'0');
}
}
//queue<ll> q;
//set<ll> s;
//priority_queue<ll> q1;
//priority_queue<ll,vector<ll>,greater<ll> > q2;
//list<ll> l;
//stack<ll> s;
ll n,m;
ll fir[E],nxt[E],son[E],tot;
double w[E],Max;
void add(ll x,ll y,double z){++tot;nxt[tot]=fir[x];son[tot]=y;fir[x]=tot;w[tot]=z;}
double dis[E],flag;
ll vis[E];
queue<int> q;
int tt[E];
ll spfa(ll s){
vis[s]=1;
q.push(s);
while(!q.empty()){
int u=q.front();q.pop();
for(ll i=fir[u];i;i=nxt[i]){
ll to=son[i];
if(dis[u]+w[i]<dis[to]){
dis[to]=dis[u]+w[i];
tt[to]++;
if(tt[to]>n+1){
puts("-1");
exit(0);
}
if(vis[to]==0){
vis[to]=1;
q.push(to);
}
}
}
vis[u]=0;
}
return 0;
}
ll st[E];
int main(){
ll T=1,S;
while(T--){
n=read();m=read();S=read();
tot=0;
memset(fir,0,sizeof(fir));
for(ll i=1;i<=m;i++){
ll x=read(),y=read();double z;
cin>>z;
add(x,y,(double)z);
}
for(ll i=0;i<=n;i++) dis[i]=2e18;
dis[S]=0;
memset(vis,0,sizeof(vis));
spfa(2);
for(ll i=0;i<=n;i++) dis[i]=2e18;
dis[S]=0;
memset(vis,0,sizeof(vis));
spfa(S);
for(ll i=1;i<=n;i++){
if(i==S) puts("0");
else if(dis[i]>=2e18) puts("NoPath");
else{
printf("%.0lf
",dis[i]);
}
}
}
return 0;
}
#10087. 「一本通 3.4 例 1」Intervals
题意
从(0sim 5 imes 10^4)中选出尽量少的整数,使每个区间([a_i,b_i])内都有至少(c_i)个数被选出。
思路
当然食用spfa啦。
设(s[k])表示0~k中至少选多少个整数。根据题意可得:
[
s[b_i]-s[a_i-1]geq c_i
]
[ s[k]-s[k-1]geq0 ]
[ s[k]-s[k-1]leq1 ]
也就是:
[
s[k-1]-s[k]geq-1
]
那么跑一次最长路就好了。
#include<algorithm>
#include<bitset>
#include<complex>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<cmath>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#define E 2000010
#define eps 1e-10
#define ll long long
using namespace std;
inline ll read(){
ll res=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
return res*f;
}
inline void write(ll x){
if(x<0) putchar('-'),x=-x;
if(x<10) putchar(x+'0');
else{
write(x/10);
putchar(x%10+'0');
}
}
//queue<ll> q;
//set<ll> s;
//priority_queue<ll> q1;
//priority_queue<ll,vector<ll>,greater<ll> > q2;
//list<ll> l;
//stack<ll> s;
ll n,m;
ll fir[E],nxt[E],son[E],tot;
double w[E];
void add(ll x,ll y,double z){++tot;nxt[tot]=fir[x];son[tot]=y;fir[x]=tot;w[tot]=z;}
double dis[E],flag;
ll vis[E];
queue<int> q;
int tt[E];
ll spfa(ll s){
vis[s]=1;
q.push(s);
while(!q.empty()){
int u=q.front();q.pop();
for(ll i=fir[u];i;i=nxt[i]){
ll to=son[i];
if(dis[u]+w[i]>dis[to]){
dis[to]=dis[u]+w[i];
tt[to]++;
if(tt[to]>n+1){
puts("-1");
exit(0);
}
if(vis[to]==0){
vis[to]=1;
q.push(to);
}
}
}
vis[u]=0;
}
return 0;
}
ll st[E],Min,Max;
int main(){
n=read();
Max=-1;Min=2e9;
for(int i=1;i<=n;i++){
ll x=read(),y=read(),z=read();
add(x-1,y,z);
Max=max(Max,y);
Min=min(Min,x-1);
}
for(int i=Min;i<=Max;i++){
add(i,i+1,0);
add(i+1,i,-1);
}
for(int i=Min;i<=Max;i++) dis[i]=-2e9;
memset(vis,0,sizeof(vis));
dis[Min]=0;
spfa(Min);
printf("%.0lf
",dis[Max]);
return 0;
}
#10088. 「一本通 3.4 例 2」出纳员问题
题意
(、、R(0)、R(1)、R(2)...R(23))表示第x个时刻需要(R(x))个出纳员,有n个出纳员申请工作,第(i)个出纳员从(t_i)时刻开始工作(8)小时,问至少需要多少出纳员?
思路
设(x[i])表示第i时刻实际上需要雇佣(x[i])人,(r[i])为第i时刻至少需要(r[i])个人。
[
x[i-7]+x[i-6]+x[i-5]+x[i-4]+x[i-3]+x[i-2]+x[i-1]+x[i]geq r[i]
]
设(s[i]=x[1]+x[2]+x[3]+...+x[i]),可得:
[
s[i]-s[i-1]geq0
]
[ s[i-1]-s[i]geq-num[i] ]
[ s[i]-s[i-8]geq r[i] ]
[ s[i]-s[i+16]geq r[i]-s[23] ]
#include<algorithm>
#include<bitset>
#include<complex>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<cmath>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#define E 2000010
#define eps 1e-10
#define ll long long
using namespace std;
inline ll read(){
ll res=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
return res*f;
}
inline void write(ll x){
if(x<0) putchar('-'),x=-x;
if(x<10) putchar(x+'0');
else{
write(x/10);
putchar(x%10+'0');
}
}
//queue<ll> q;
//set<ll> s;
//priority_queue<ll> q1;
//priority_queue<ll,vector<ll>,greater<ll> > q2;
//list<ll> l;
//stack<ll> s;
ll n,m;
ll fir[E],nxt[E],son[E],tot;
int w[E];
void add(ll x,ll y,ll z){++tot;nxt[tot]=fir[x];son[tot]=y;fir[x]=tot;w[tot]=z;}
int dis[E],flag;
ll vis[E];
queue<int> q;
int tt[E];
ll spfa(ll s){
memset(dis,63,sizeof(dis));
memset(tt,0,sizeof(tt));
memset(vis,0,sizeof(vis));
dis[24]=0;
vis[24]=1;
q.push(24);
while(!q.empty()){
int u=q.front();q.pop();
for(ll i=fir[u];i;i=nxt[i]){
ll to=son[i];
if(dis[u]+w[i]<dis[to]){
dis[to]=dis[u]+w[i];
tt[to]++;
if(tt[to]>n+1){
return 0;
}
if(vis[to]==0){
vis[to]=1;
q.push(to);
}
}
}
vis[u]=0;
}
return dis[0]==-s;
}
ll T,r[E],Min,Max,s[E],num[E];
void work(int x){
memset(fir,0,sizeof(fir));tot=0;
for(register int i=1;i<=24;i++) add(i,i-1,0),add(i-1,i,num[i]);
for(register int i=8;i<=24;i++) add(i,i-8,-r[i]);
for(register int j=1;j<=7;j++) add(j,j+16,x-r[j]);
add(24,0,-x);
}
int main(){
T=read();
while(T--){
for(int i=1;i<=24;i++){
r[i]=read();num[i]=0;
}
n=read();
for(int i=1;i<=n;i++){
int t=read();t++;
num[t]++;
}
int l=0,r=n,ans=2e9;
while(l<=r){
int mid=(l+r)/2;
work(mid);
if(spfa(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
if(ans==2e9) puts("No Solution");
else write(ans),putchar('
');
}
return 0;
}
#10089. 「一本通 3.4 练习 1」糖果
题意
满足条件:
如果 X=1.表示第 A 个小朋友分到的糖果必须和第 B 个小朋友分到的精果一样多。
如果 X=2,表示第 A 个小朋友分到的糖果必须少于第 B 个小朋友分到的糖果。
如果 X=3,表示第 A 个小朋友分到的糖果必须不少于第 B 个小朋友分到的糖果。
如果 X=4,表示第 A 个小朋友分到的糖果必须多于第 B 个小朋友分到的糖果。
如果 X=5,表示第 A 个小朋友分到的糖果必须不多于第 B 个小朋友分到的糖果。
求至少需要准备的糖果数?
思路
如果 X=1
[
B=A
]
如果 X=2
[
B+1ge A
]
如果 X=3
[
Age B
]
如果 X=4
[
A-1ge B
]
如果 X=5
[
B ge A
]
那么就好了嘛:
#include<algorithm>
#include<bitset>
#include<complex>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<cmath>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#define E 300010
#define eps 1e-10
#define ll long long
#pragma GCC optimize(2)
using namespace std;
inline ll read(){
ll res=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
return res*f;
}
inline void write(ll x){
if(x<0) putchar('-'),x=-x;
if(x<10) putchar(x+'0');
else{
write(x/10);
putchar(x%10+'0');
}
}
//queue<ll> q;
//set<ll> s;
//priority_queue<ll> q1;
//priority_queue<ll,vector<ll>,greater<ll> > q2;
//list<ll> l;
//stack<ll> s;
ll n,k;
ll fir[E],nxt[E],son[E],w[E],tot,inf,ans;
inline void add(register ll x,register ll y,register ll z){
++tot;
w[tot]=z;
nxt[tot]=fir[x];
fir[x]=tot;
son[tot]=y;
}
ll dis[E],vis[E],tt[E];
deque<ll> q;
inline void spfa(){
memset(dis,0,sizeof(dis));
memset(tt,0,sizeof(tt));
memset(vis,0,sizeof(vis));inf=dis[0];
dis[0]=0;vis[0]=1;
while(!q.empty()) q.pop_front();
q.push_back(0);
while(!q.empty()){
register ll u=q.front();q.pop_front();
vis[u]=0;
for(register ll i=fir[u];i;i=nxt[i]){
register ll to=son[i];
if(dis[to]<dis[u]+w[i]){
tt[to]++;
dis[to]=dis[u]+w[i];
if(tt[to]>n+1){
puts("-1");
exit(0);
}
if(!vis[to]){
vis[to]=1;
if(!q.empty()&&dis[to]<dis[q.front()]) q.push_front(to);
else q.push_back(to);
}
}
}
}
}
int main(){
n=read();k=read();
for(register ll i=1;i<=k;i++){
ll x=read(),a=read(),b=read();
if(a==b&&(x==2||x==4)){
puts("-1");
return 0;
}
if(x==1) add(a,b,0),add(b,a,0);
if(x==2) add(a,b,1);
if(x==3) add(b,a,0);
if(x==4) add(b,a,1);
if(x==5) add(a,b,0);
}
for(register ll i=1;i<=n;i++) add(0,i,1);
spfa();
for(register ll i=1;i<=n;i++){
ans+=dis[i];
}
write(ans);putchar('
');
return 0;
}
#10090. 「一本通 3.4 练习 2」布局 Layout
题意
有些奶牛是好基友,它们希望彼此之间的距离小于等于某个数。有些奶牛是情敌,它们希望彼此之间的距离大于等于某个数。
思路
如果两只奶牛是好基友,那么:
[
A-Bleq D
]
如果两只奶牛是情敌,那么:
[
A-Bge D
]
即:
[
Dleq A-B
]
也就是:
[
B-Aleq -D
]
直接上代码:
#include<algorithm>
#include<bitset>
#include<complex>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<cmath>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#define E 300010
#define eps 1e-10
#define ll long long
#pragma GCC optimize(2)
using namespace std;
inline ll read(){
ll res=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
return res*f;
}
inline void write(ll x){
if(x<0) putchar('-'),x=-x;
if(x<10) putchar(x+'0');
else{
write(x/10);
putchar(x%10+'0');
}
}
//queue<ll> q;
//set<ll> s;
//priority_queue<ll> q1;
//priority_queue<ll,vector<ll>,greater<ll> > q2;
//list<ll> l;
//stack<ll> s;
ll n,k;
ll fir[E],nxt[E],son[E],w[E],tot,inf,ans;
inline void add(register ll x,register ll y,register ll z){
++tot;
w[tot]=z;
nxt[tot]=fir[x];
fir[x]=tot;
son[tot]=y;
}
ll dis[E],vis[E],tt[E];
deque<ll> q;
inline void spfa(int s){
memset(dis,63,sizeof(dis));
memset(tt,0,sizeof(tt));
memset(vis,0,sizeof(vis));inf=dis[0];
dis[s]=0;vis[s]=1;
while(!q.empty()) q.pop_front();
q.push_back(s);
while(!q.empty()){
register ll u=q.front();q.pop_front();
vis[u]=0;
for(register ll i=fir[u];i;i=nxt[i]){
register ll to=son[i];
if(dis[to]>dis[u]+w[i]){
tt[to]++;
dis[to]=dis[u]+w[i];
if(tt[to]>n+1){
puts("-1");
exit(0);
}
if(!vis[to]){
vis[to]=1;
if(!q.empty()&&dis[to]<dis[q.front()]) q.push_front(to);
else q.push_back(to);
}
}
}
}
}
int k1,k2;
int main(){
n=read();k1=read();k2=read();
for(register ll i=1;i<=k1;i++){
ll x=read(),y=read(),z=read();
add(x,y,z);
}
for(register ll i=1;i<=k2;i++){
ll x=read(),y=read(),z=read();
add(y,x,-z);
}
spfa(1);
ans=dis[n];
for(int i=1;i<=n;i++) spfa(i);
if(ans>=inf) puts("-2");
else write(ans),putchar('
');
return 0;
}
以上是关于LibreOJ刷题计划 &《信息学奥赛一本通》提高版题目的主要内容,如果未能解决你的问题,请参考以下文章