10.23爆零题解
T1超级大水题,结果忘了输出“\n”,爆零;
T2网络流+二分,结果忘了memcpy(),爆零;
T3,嗯,不会。
T1. LMY与LYM
问题描述:
LMY与LYM在玩一个数字游戏,一开始黑板上写有两个整数n,m。LMY先手,LMY和LYM轮流操作,每人都可以将当前的n加上n的一个正因数d,变成n+d,第一个将n变成一个大于m的数的人输掉比赛。现在给出两个数n,m;LMY和LYM都非常聪明,问谁会获胜?
输入:
有多组测试数据:
第一行一个整数T,表示有T组数据。
第二行到第T+1行,每行两个整数,分别表示n,m。
输出:
输出T行,若LMY赢,输出“LMY beats LYM”; 若LYM赢,输出“LYM beats LMY”;
样例输入输出:
1
2 3
LMY beats LYM
数据范围:
30%数据: T<10; n<10;m<100;
100%数据:T<=213;n<=231-1, n
#include<iostream>
using namespace std;
long long n,m,T;
int main()
{
//freopen("lmym.in","r",stdin);
//freopen("lmym.out","w",stdout);
scanf("%lld",&T);
for(int i=1;i<=T;i++)
{
scanf("%lld%lld",&n,&m);
if(n&1)printf("LYM beats LMY\n");
else printf("LMY beats LYM\n");
}
}
题解:此题极水,上个厕所随便枚举几个数就找到规律,就只需要判断奇偶即可,不要忘了换行TAT。
T2. 河城荷取
问题描述:
在幻想乡,河城荷取是擅长高科技工业的河童。荷取的得意之作是巨型人形机械『非想天则』。不过由于人形太过巨大,所以为它充能是一件很麻烦的事。
人形一共有 N 个电能池,编号 1..N。其中前 L 个电能池(即编号为 1..L 的电能池)连接着外部充能接口,而编号为 N 的电能池连接着动力炉核心。在 N 个蓄能池之间有 M 条单向管道,每条管道有一个激活代价cost和电能传输极限limit。当激活度达到某个值时,所有激活代价小于等于这个值的管道都会被激活,但是每一条管道一时只能够最多传送 limit个单位的电能。外部接口到电能池和电能池到动力炉核心的管道传输没有限制并且激活代价为 0。现在荷取想往动力炉核心输入至少K个单位的电能,求需要的最小激活度。
输入:
第 1 行:4 个正整数 N,M,L, K
第 2..M+1 行:4 个整数,u,v,limit,cost,表示一条由 u 到 v 的管道,传输极限 limit,激活代价 为 cost
输出:
第 1 行:1 个整数,表示最小激活代。
样例输入:
6 5 3 3
1 4 2 4
2 4 3 5
3 5 4 2
4 6 2 3
5 6 3 4
4
样例说明:
数据范围:
对于 30%的数据:1 ≤ L ≤ N ≤ 100,0 ≤ M ≤ 2,000,1 ≤ cost ≤ 10,000
对于 60%的数据:1 ≤ L ≤ N ≤ 1,000,0 ≤ M ≤ 20,000,1 ≤ cost ≤ 10,000
对于 100%的数据:1 ≤ L ≤ N ≤ 2,000,0 ≤ M ≤ 80,000,1 ≤ cost ≤ 1,000,000
对于 100%的数据:1 ≤ limit ≤ 1,000
保证任意(u,v)都只出现一次。
题解:建图网络流,二分枚举最大花费,每次讨论要重新读图!;
代码如下:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int inf=1e9,maxn=2017,maxm=80050;
int ma[maxn][maxn],g[maxn][maxn],c[maxn][maxn],cnt[maxm],dis[maxm],flow,ans;
int n,m,L,k,lim,cos,x,y,st,maxx=0,w[maxm],xxx;
inline void re(int &d)
{
bool f=false;char t=getchar();
while(t<'0'||t>'9'){if(t=='-')f=true;t=getchar();}
for(d=0;t>='0'&&t<='9';t=getchar())d=(d<<1)+(d<<3)+t-'0';
d=(f?(-d):(d));
}
int dfs(int u,int flow,int maxcost){
int v,temp,delta=0;
if(u==n)return flow;
for(v=1;v<=n;v++){
if(g[u][v]&&dis[u]==dis[v]+1&&c[u][v]<=maxcost)
{
temp=dfs(v,min(flow-delta,g[u][v]),maxcost);
g[u][v]-=temp;
g[v][u]+=temp;
delta+=temp;
if(delta==flow||dis[st]>=n)return delta;
}
}
if(dis[st]>n)return delta;
cnt[dis[u]]--;
if(cnt[dis[u]]==0)dis[st]=n;
dis[u]++;
cnt[dis[u]]++;
return delta;
}
bool ok(int x)
{
memcpy(g,ma,sizeof(ma));
memset(cnt,0,sizeof(cnt));
memset(dis,0,sizeof(dis));
int tmp,ans=0;
while(dis[st]<n)
{
tmp=dfs(st,inf,x);
ans+=tmp;
}
if(ans>=k)return true;
else return false;
}
void work1()
{
int l=0,r=m,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(ok(w[mid]))r=mid-1;
else l=mid+1;
}
xxx=l;
}
int main()
{
st=0;
re(n);re(m);re(L);re(k);
for(int i=1;i<=m;i++)
{
re(x);re(y);re(lim);re(cos);
ma[x][y]=lim;
w[i]=c[x][y]=cos;
}
for(int i=1;i<=L;i++)ma[0][i]=inf,c[0][i]=0;
sort(w+1,w+1+m);
work1();
printf("%d",w[xxx]);
}
T3. 最短路径
问题描述:
平面内给出 n 个点,记横坐标最小的点为 A,最大的点为 B,现在小 Y 想要知道在 每个点经过一次(A 点两次)的情况下从 A 走到 B,再回到 A 的最短路径。但他是个强迫症患者,他有许多奇奇怪怪的要求与限制条件:
1.从 A 走到 B 时,只能由横坐标小的点走到大的点。
2.由 B 回到 A 时,只能由横坐标大的点走到小的点。
3.有两个特殊点 b1 和 b2, b1 在 0 到 n-1 的路上,b2 在 n-1 到 0 的路上。 请你帮他解决这个问题助他治疗吧!
样例输入输出:
5 1 3
1 3
3 4
4 1
7 5
8 3
18.18
代码。。。如下:
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1007,inf=1e9;
struct point{
int x;int y;
}poi[maxn];
double dis(int a,int b)
{
return sqrt((poi[a].x-poi[b].x)*(poi[a].x-poi[b].x)+(poi[a].y-poi[b].y)*(poi[a].y-poi[b].y));
}
double f[maxn][maxn];
int n,b1,b2,i,j;
int main()
{
memset(f,0x7f,sizeof(f));f[1][1]=0;
scanf("%d%d%d",&n,&b1,&b2);
b1++;b2++;
for(i=1;i<=n;i++)scanf("%d%d",&poi[i].x,&poi[i].y);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i==1||i!=j)
{
int k=1;
double tmp;
k+=max(i,j);
if(k==n+1)
{
if(j==n)
{
tmp=dis(i,n);
f[n][n]=(f[n][n]<tmp?(f[n][n]):(f[i][j]+tmp));
}
else if(i==n)
{
tmp=dis(j,n);
f[n][n]=(f[n][n]<tmp?(f[n][n]):(f[i][j]+tmp));
}
continue;
}
if(k!=b1)f[i][k]=min(f[i][k],f[i][j]+dis(j,k));
if(k!=b2)f[k][j]=min(f[k][j],f[i][j]+dis(i,k));
}
printf("%.2lf",f[n][n]);
}