真就一题进复赛呗。
签到模拟题。注意是收回的钱向下取整,如果你直接算钱的消耗量,是要向上取整的。
#include
using namespace std;
int t,n,m,p,ans,re;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin>>t;
while(t--)
{
ans=0;
cin>>n>>m>>p;
p=100-p;
while(n>=m)
{
re=m*p/100;
n=n-m+re;
ans++;
}
cout<<ans<<endl;
}
}
题目整的很玄乎,当朋友全在同一方向的一条直线上时距离和就是最短的。
#include
#define int long long
using namespace std;
const int maxn=1e5+7;
int t,n,a[maxn],ans;
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin>>t;
while(t--)
{
ans=0;
cin>>n;
for(int i=1;i<=n;++i)
cin>>a[i];
sort(a+1,a+n+1);
for(int i=1;i<n;++i)
ans+=i*(n-i)*(a[i+1]-a[i]);
cout<<ans<<endl;
}
}
建图g,存每个时间每个地点的人。建图p,存每个人的行动轨迹。然后深搜,打标记。
#include
#define int long long
using namespace std;
typedef pair<int,int> P;
const int maxn=2e4+1;
vector<int> g[101][11];
vector<P> p[maxn];
int t,n,len,u,v,vir[maxn],vis[101][11];
void dfs(int tt,int pp)
{
for(auto ppp:g[tt][pp])
{
vir[ppp]=1;
for(auto path:p[ppp])
{
if(!vis[path.first][path.second]&&path.first>tt)
{
vis[path.first][path.second]=1;
dfs(path.first,path.second);
}
}
}
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin>>t;
for(int cas=1;cas<=t;++cas)
{
memset(vis,0,sizeof(vis));
memset(vir,0,sizeof(vir));
for(int i=1;i<=n;++i)
p[i].clear();
for(int i=1;i<=100;++i)
for(int j=1;j<=10;++j)
g[i][j].clear();
cin>>n;
for(int i=1;i<=n;++i)
{
cin>>len;
for(int j=1;j<=len;++j)
{
cin>>u>>v;
g[u][v].push_back(i);
p[i].push_back(make_pair(u,v));
}
}
for(auto pp:p[1])
{
if(!g[pp.first][pp.second].empty())
dfs(pp.first,pp.second);
}
int first=1;
for(int i=1;i<=n;++i)
if(vir[i])
{
if(first)
{
cout<<i;
first=0;
}
else
{
cout<<" "<<i;
}
}
cout<<endl;
}
}
暴搜,优化,卡时限。求不限行最小的最大值,只需要先求限行最大的最小值,然后用n减去它就行。当然这题标程应该是二分答案,不过我懒 。
#include
using namespace std;
int t,n,x,cnt[12],sum[12],ans;
inline int redn()
{
int ret=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-f;ch=getchar();}
while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
void dfs(int num)
{
if(num==10)
{
ans=max(ans,*min_element(sum,sum+5));
return;
}
for(int i=0;i<5;++i)
{
sum[i]+=cnt[num];
dfs(num+1);
sum[i]-=cnt[num];
}
}
signed main()
{
t=redn();
while(t--)
{
memset(cnt,0,sizeof(cnt));
memset(sum,0,sizeof(sum));
ans=0;
n=redn();
for(int i=1;i<=n;++i)
{
scanf("%d",&x);
++cnt[x%10];
}
dfs(0);
printf("%d\n",n-ans);
}
}
和第一场初赛那道Mosquito差不多,不过这次是最大费用最大流,依然是借了个板子改的。
喜好的组合一共就只有6种,把n个人压缩成6种喜好状态,并cnt每个状态有多少人。从源点S向每个状态连容量为该状态人数,费用为0的边,再从每种状态向三种饮料建容量无限,费用为状态与对应饮料的快乐值,最后从三种饮料向汇点T连容量为该种饮料个数,费用为0的边。
如上修改后,把初始cost全设为0,因为是最大费用,把SPFA的条件改成了cost[e.to]
#include
const int MAXN=1e5+7;
const int inf=0x3f3f3f3f;
using namespace std;
int ls[][3]={{0,0,0},{3,2,1},{3,1,2},{2,3,1},{1,3,2},{2,1,3},{1,2,3}};
bool vis[MAXN];
int n, m, s, t;
int u, v, c, w;
int cost[MAXN], pre[MAXN], last[MAXN], flow[MAXN];
int maxFlow, minCost;
struct Edge
{
int from, to, flow, cost;
}edge[MAXN];
int head[MAXN], num_edge;
queue <int> q;
void addedge(int from, int to, int flow, int cost)
{
edge[++num_edge].from = head[from];
edge[num_edge].to = to;
edge[num_edge].flow = flow;
edge[num_edge].cost = cost;
head[from] = num_edge;
edge[++num_edge].from = head[to];
edge[num_edge].to = from;
edge[num_edge].flow = 0;
edge[num_edge].cost = -cost;
head[to] = num_edge;
}
bool SPFA(int s, int t)
{
memset(cost, 0, sizeof(cost));
memset(flow, 0x7f, sizeof(flow));
memset(vis, 0, sizeof(vis));
q.push(s); vis[s] = 1; cost[s] = 0; pre[t] = -1;
while (!q.empty())
{
int now = q.front();
q.pop();
vis[now] = 0;
for (int i = head[now]; i != -1; i = edge[i].from)
{
if (edge[i].flow>0 && cost[edge[i].to]<cost[now] + edge[i].cost)
{
cost[edge[i].to] = cost[now] + edge[i].cost;
pre[edge[i].to] = now;
last[edge[i].to] = i;
flow[edge[i].to] = min(flow[now], edge[i].flow);
if (!vis[edge[i].to])
{
vis[edge[i].to] = 1;
q.push(edge[i].to);
}
}
}
}
return pre[t] != -1;
}
void MCMF()
{
while (SPFA(s, t))
{
int now = t;
maxFlow += flow[t];
minCost += flow[t] * (cost[t]-2);
while (now != s)
{
edge[last[now]].flow -= flow[t];
edge[last[now] ^ 1].flow += flow[t];
now = pre[now];
}
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int cas,nn,a,b,c;
cin>>cas;
while(cas--)
{
maxFlow=minCost=0;
memset(head, -1, sizeof(head)); num_edge = -1;
cin>>nn>>a>>b>>c;
int cnt[10]={0};
string ss;
for(int i=1;i<=nn;++i)
{
cin>>ss;
if(ss=="012") ++cnt[1];
if(ss=="021") ++cnt[2];
if(ss=="102") ++cnt[3];
if(ss=="120") ++cnt[4];
if(ss=="201") ++cnt[5];
if(ss=="210") ++cnt[6];
}
n=11,m=27,s=0,t=10;
for(int i=1;i<=6;++i)
if(cnt[i])
{
addedge(0,i,cnt[i],1);
addedge(i,7,inf,ls[i][0]);
addedge(i,8,inf,ls[i][1]);
addedge(i,9,inf,ls[i][2]);
}
addedge(7,10,a,1);
addedge(8,10,b,1);
addedge(9,10,c,1);
MCMF();
cout<<minCost<<endl;
}
}
(我认为的)粪题,对拍跑了一晚上不出结果,直接放弃。
贴个别人的代码,作者原文:https://blog.csdn.net/a_forever_dream/article/details/107743001
#include
using namespace std;
int T;
double a,b,x;
int main()
{
scanf("%d",&T);while(T--)
{
scanf("%lf %lf %lf",&a,&b,&x);
if(x>b)
{
double c=sqrt(x*x-b*b);
if(2*c<x){
int k=floor(a/x);int ans=2*k+1;
double X=a-k*x,Y=X-(x-c);
if(X>=c)ans++,Y=X-c;
if(sqrt(x*x-X*X)+sqrt(x*x-Y*Y)<=b)ans++;
printf("%d\n",ans);
}
else printf("%d\n",(int)(a/c)+1);
}
else
{
int ans1,ans2;
ans1=(int)(a/x)+1;
double c=a-1.0*(ans1-1)*x;
c=sqrt((double)(x*x-c*c));
if(b-c*2>=x)ans2=(int)((b-c*2-x)/x)+2;
else if(b-c*2>=0)ans2=1;
else ans2=0;
printf("%d\n",ans1*2+ans2);
}
}
}
DP,在最优的策略中,Alice要想办法浪费Bob的每一秒时间,也就是说如果Alice可以抢在Bob前完成某提,一定会等到Bob做出来的一瞬间提交,避免提前题解而让Bob跳过了这题。因为Bob不会跳过,所以完成每一题的时间就固定了下来,对数组b做前缀和即可。用f[i][j]
记录Alice到第i题为止,得分为j,最少用时是多少。递推的过程为,如果Alice能赶在Bob之前做出第i题,f[i][j]=min(f[i-1][j],f[i-1][j-1]+a[i])
,否则f[i][j]=f[i-1][j]
。请注意f存储的是时间,而题目中时间最大达到了1e18,定义inf如果用0x3f3f3f3f会WA。
#include
#define int long long
using namespace std;
const int maxn=2010;
const int inf=1e18+7;
int n,a[maxn]= {0},b[maxn]= {0},f[maxn][maxn]= {0};
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int cas;
cin>>cas;
while(cas--)
{
cin>>n;
for(int i=1; i<=n; ++i)
cin>>a[i];
for(int i=1; i<=n; ++i)
{
cin>>b[i];
b[i]+=b[i-1];
}
for(int i=0; i<=n; ++i)
for(int j=0; j<=n; ++j)
f[i][j]=inf;
f[0][0]=0;
for(int i=1; i<=n; ++i)
for(int j=0; j<=i; ++j)
if(!j||f[i-1][j-1]+a[i]>b[i])
f[i][j]=f[i-1][j];
else
f[i][j]=min(f[i-1][j],f[i-1][j-1]+a[i]);
for(int i=n; i>=1; --i)
if(f[n][i]!=inf)
{
cout<<i<<endl;
break;
}
}
}
0个AC,你懂的。