[2020年百度之星·程序设计大赛-初赛二]Coda的题解集

真就一题进复赛呗。


Poker

签到模拟题。注意是收回的钱向下取整,如果你直接算钱的消耗量,是要向上取整的。

#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;
    }
}

Distance

题目整的很玄乎,当朋友全在同一方向的一条直线上时距离和就是最短的。

#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;
    }
}

Covid

建图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;
    }
}

Car

暴搜,优化,卡时限。求不限行最小的最大值,只需要先求限行最大的最小值,然后用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);
    }
}

Drink

和第一场初赛那道Mosquito差不多,不过这次是最大费用最大流,依然是借了个板子改的。
喜好的组合一共就只有6种,把n个人压缩成6种喜好状态,并cnt每个状态有多少人。从源点S向每个状态连容量为该状态人数,费用为0的边,再从每种状态向三种饮料建容量无限,费用为状态与对应饮料的快乐值,最后从三种饮料向汇点T连容量为该种饮料个数,费用为0的边。
如上修改后,把初始cost全设为0,因为是最大费用,把SPFA的条件改成了cost[e.to] 最后我把源点S的出边和汇点T的入边从0改成了1,因为一条增广路只会经过一次S出边和一次T入边,修改之后在统计每条费用的时候都减去这两点多出来的费用即可。

#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;
    }
}

Cloth

(我认为的)粪题,对拍跑了一晚上不出结果,直接放弃。
贴个别人的代码,作者原文: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);
        }
    }
}

Solo

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;
            }
    }
}

Hanoi

0个AC,你懂的。

你可能感兴趣的:([2020年百度之星·程序设计大赛-初赛二]Coda的题解集)