场上差点4题……
补题进度[5/10] 场上3题
A gpa
变一下式子发现就是01分数规划&这下不会忘了、
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mod 1000000007
const int maxn = 1e5 + 5;
const double eps = 1e-6;
double s[maxn],c[maxn];
int n,k;
double a[maxn];
bool check(double mid)
{
for(int i = 0;i<n;i++)
{
a[i] = s[i]*c[i] - s[i]*mid;
}
sort(a,a+n,[](double x,double y){return x > y;});
double sum = 0;
for(int i = 0;i < n - k;i++)
{
sum += a[i];
}
return sum >= 0;
}
int main ()
{
cin>>n>>k;
for(int i = 0;i<n;i++)
{
cin>>s[i];
}
for(int j = 0;j<n;j++)
{
cin>>c[j];
}
double l = 0.0,r = 1e12+5;
while(r - l > eps)
{
double mid =(l + r) /2;
if(check(mid))
{
l = mid;
}
else r = mid;
}
cout<<fixed<<setprecision(12)<<r<<endl;
return 0;
}
E room
题意是搬宿舍,给出原来的住宿情况和之后的申请情况,问最少几个人交换就行了。
想了一下这样建图,原来的房间在左边,之后的申请看作是虚拟的房间,在右边,那么对于左边的点,连一条和对应的虚拟房间的交集(就是i中有多少个人到j这个宿舍) 然后就是二分图最大权匹配的问题了。
套了km算法的板子,其实费用流求最大费用也ok
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
using namespace std;
const int N = 510;
const int INF = 0x3f3f3f3f;
int nx,ny;//两边的点数
int g[N][N];//二分图描述
int linker[N],lx[N],ly[N];//y中各点匹配状态,x,y中的点标号
int slack[N];
bool visx[N],visy[N];
bool DFS(int x)
{
visx[x] = true;
for(int y = 0; y < ny; y++)
{
if(visy[y])
continue;
int tmp = lx[x] + ly[y] - g[x][y];
if(tmp == 0)
{
visy[y] = true;
if(linker[y] == -1 || DFS(linker[y]))
{
linker[y] = x;
return true;
}
}
else if(slack[y] > tmp)
slack[y] = tmp;
}
return false;
}
int KM()
{
memset(linker,-1,sizeof(linker));
memset(ly,0,sizeof(ly));
for(int i = 0; i < nx; i++)
{
lx[i] = -INF;
for(int j = 0; j < ny; j++)
if(g[i][j] > lx[i])
lx[i] = g[i][j];
}
for(int x = 0; x < nx; x++)
{
for(int i = 0; i < ny; i++)
slack[i] = INF;
while(true)
{
memset(visx,false,sizeof(visx));
memset(visy,false,sizeof(visy));
if(DFS(x))
break;
int d = INF;
for(int i = 0; i < ny; i++)
if(!visy[i] && d > slack[i])
d = slack[i];
for(int i = 0; i < nx; i++)
if(visx[i])
lx[i] -= d;
for(int i = 0; i < ny; i++)
{
if(visy[i])
ly[i] += d;
else
slack[i] -= d;
}
}
}
int res = 0;
for(int i = 0; i < ny; i++)
if(linker[i] != -1)
res += g[linker[i]][i];
return res;
}
int x[N][5],y[N][5];
int main()
{
int n;
scanf("%d", &n);
for(int i = 1; i<=n; i++)
{
for(int j = 1; j<=4; j++)
scanf("%d",&x[i][j]);
}
for(int i = 1; i<=n; i++)
{
for(int j = 1; j<=4; j++)
scanf("%d",&y[i][j]);
}
nx = ny = n;
for(int i = 1; i<=n; i++)
{
for(int j = 1; j<=n; j++)
{
int c = 0;
for(int k = 1; k<=4; k++)
{
for(int l = 1; l<=4; l++)
{
if(x[i][k] == y[j][l])
c++;
}
}
g[i-1][j-1] = c;
}
}
int cost = KM();
//int ans = minCostMaxflow(st,en,cost);
//print();
printf("%d\n",n*4-cost);
return 0;
}
费用流版本:
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 10000;
const int MAXM = 100000;
const int INF = 0x3f3f3f3f;
struct Edge
{
int from,to,next,cap,flow,cost;
} edge[MAXM];
int head[MAXN],tol;
int pre[MAXN],dis[MAXN];
bool vis[MAXN];
int N;//节点总个数,节点编号从0~N-1
void init(int n)
{
N = n;
tol = 0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int cap,int cost)
{
edge[tol].to = v;
edge[tol].from = u;
edge[tol].cap = cap;
edge[tol].cost = cost;
edge[tol].flow = 0;
edge[tol].next = head[u];
head[u] = tol++;
edge[tol].to = u;
edge[tol].from = v;
edge[tol].cap = 0;
edge[tol].cost = -cost;
edge[tol].flow = 0;
edge[tol].next = head[v];
head[v] = tol++;
}
bool spfa(int s,int t)
{
queue<int>q;
for(int i = 0; i < N; i++)
{
dis[i] = INF;
vis[i] = false;
pre[i] = -1;
}
dis[s] = 0;
vis[s] = true;
q.push(s);
while(!q.empty())
{
int u = q.front();
q.pop();
vis[u] = false;
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if(edge[i].cap > edge[i].flow &&
dis[v] > dis[u] + edge[i].cost )
{
dis[v] = dis[u] + edge[i].cost;
pre[v] = i;
if(!vis[v])
{
vis[v] = true;
q.push(v);
}
}
}
}
if(pre[t] == -1)
return false;
else
return true;
}
//返回的是最大流,cost存的是最小费用
int minCostMaxflow(int s,int t,int &cost)
{
int flow = 0;
cost = 0;
while(spfa(s,t))
{
int Min = INF;
for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])
{
if(Min > edge[i].cap - edge[i].flow)
Min = edge[i].cap - edge[i].flow;
}
for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])
{
edge[i].flow += Min;
edge[i^1].flow -= Min;
cost += edge[i].cost * Min;
}
flow += Min;
}
return flow;
}
void print()
{
for(int i = 0;i<tol;i += 2)
{
printf("%d -> %d flow = %d cap = %d cost = %d\n",edge[i].from,edge[i].to,edge[i].flow,edge[i].cap,edge[i].cost);
}
}
int x[101][5],y[101][5];
int main()
{
int n;
scanf("%d", &n);
init(2*n+2);
for(int i = 1;i<=n;i++)
{
for(int j = 1;j<=4;j++) scanf("%d",&x[i][j]);
}
for(int i = 1;i<=n;i++)
{
for(int j = 1;j<=4;j++) scanf("%d",&y[i][j]);
}
int st = 0,en = 2*n +1;
for(int i = 1;i<=n;i++)
{
addedge(st,i,1,0);
addedge(i+n,en,1,0);
for(int j = 1;j<=n;j++)
{
int c = 0;
for(int k = 1;k<=4;k++)
{
for(int l = 1;l<=4;l++)
{
if(x[i][k] == y[j][l]) c++;
}
}
addedge(i,j+n,1,4 - c); //直接最小化需要搬出去的人数
}
}
int cost = 0;
int ans = minCostMaxflow(st,en,cost);
//print();
printf("%d\n",cost);
return 0;
}
J plan
这道题就是一贪心,我的做法和std差不多,没想到判断了几个情况就过了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mod 1000000007
int main ()
{
int n,p2,p3;
cin>>n>>p2>>p3;
int t2 = (n + 2-1)/2;
int t3 = (n + 3-1)/3;
ll ans = min((ll)p2*t2,(ll)p3*t3);
if(n % 2 == 1) ans = min(ans,(ll)(t2 - 2)*p2+p3);
if(n % 3 == 1) ans = min(ans,(ll)(t3 - 2)*p3 + 2*p2);
if(n % 3 == 2) ans = min(ans,(ll)(t3 - 1)*p3 + p2);
cout<<ans<<endl;
return 0;
}
G max
队友直接暴力了,其实只要取m = n/c m*(m-1) 判断一下特殊情况就ok
#include <cstdio>
#include <algorithm>
#include <vector>
#include <iostream>
#include <set>
#include <map>
#include <cstring>
#include <cmath>
#define ll long long
using namespace std;
int main()
{
long long n,c;
cin>>c>>n;
n/=c;
for(long long i=n+n;i>=2;i--){
for(long long j=int(i/2);j<=n&&j<i;j++){
if(__gcd(j,i-j)==1) return cout<<c*c*j*(i-j)<<endl,0;
}
}
cout<<-1<<endl;
return 0;
}
F take
首先能想到一个点贡献的期望是前面都比他大的期望,首先按照价值对钻石排序,然后离线操作,每次添加之前先查询一下这个位置前面的拿不到的概率的前缀积,更新答案之后插入。这样就可以保证查询的时候,比当前大的已经插入了。
#include <bits/stdc++.h>
#define pr pair<ll,ll>
#define fi first
#define se second
#define ll long long
using namespace std;
const int maxn = 1<<17;
const ll mod = 998244353;
ll pow_mod(ll a,ll n)
{
ll res = 1,b = a % mod;
while(n)
{
if(n & 1) res = res * b % mod;
b = b * b % mod;
n>>=1;
}
return res;
}
ll bit[maxn];
int lowbit(int x)
{
return x & (-x);
}
void add(int x,ll c)
{
for(int i = x ; i< maxn; i += lowbit(i))
{
bit[i] = bit[i]*c% mod;
}
}
ll prd(int x)
{
ll res = 1;
for(int i = x ;i ;i -= lowbit(i)) res = (res *bit[i])% mod;
return res;
}
struct node
{
int p,d,id;
}a[maxn];
int main()
{
ll inv = pow_mod(100,mod-2);
int n;
scanf("%d",&n);
for(int i = 0;i<maxn;i++) bit[i] = 1;
for(int i = 0;i<n;i++)
{
a[i].id = i+1;
scanf("%d%d", &a[i].p, &a[i].d);
}
sort(a,a+n,[](const node &x,const node &y)
{
if(x.d == y.d) return x.id < y.id;
else return x.d > y.d;
});
ll ans = 0;
for(int i = 0;i<n;i++)
{
ll tmp = (prd(a[i].id - 1)* ((a[i].p*inv) % mod))% mod;
// cout<<tmp<<endl;
ans = (ans + tmp) % mod;
add(a[i].id,inv*(100 - a[i].p)% mod);
}
printf("%lld\n",ans);
return 0;
}