FR #1题解

A.

  建图跑最小费用最大流。分类讨论每种情况如何连边,费用怎么定。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define maxv 105
#define maxe 100500
#define inf 1000000000
using namespace std;
int n,m,a[maxv],b[maxv],c[maxv],d[maxv],s,t,fin[maxv],fout[maxv],g[maxv],dis[maxv],nume=1,ans=0,pree[maxv],prev[maxv];
bool vis[maxv];
queue <int> q;
struct edge
{
    int v,f,c,nxt;
}e[maxe];
void addedge(int u,int v,int f,int c)
{
    e[++nume].v=v;e[nume].nxt=g[u];
    e[nume].f=f;e[nume].c=c;g[u]=nume;
    e[++nume].v=u;e[nume].nxt=g[v];
    e[nume].f=0;e[nume].c=-c;g[v]=nume;
}
bool spfa()
{
    for (int i=s;i<=t;i++) {vis[i]=false;dis[i]=inf;}
    dis[s]=0;q.push(s);
    while (!q.empty())
    {
        int head=q.front();q.pop();
        for (int i=g[head];i;i=e[i].nxt)
        {
            int v=e[i].v;
            if ((e[i].f) && (dis[v]>dis[head]+e[i].c))
            {
                dis[v]=dis[head]+e[i].c;
                pree[v]=i;prev[v]=head;
                if (!vis[v]) {vis[v]=true;q.push(v);}
            }
        }
        vis[head]=false;
    }
    if (dis[t]==inf) return false;
    return true;
}
int dinic()
{
    int u=t,dt=inf;
    while (u!=s)
    {
        dt=min(dt,e[pree[u]].f);
        u=prev[u];
    }
    u=t;
    while (u!=s)
    {
        e[pree[u]].f-=dt;
        e[pree[u]^1].f+=dt;
        u=prev[u];
    }
    return dis[t]*dt;
}
int main()
{
    scanf("%d%d",&n,&m);s=0;t=n+1;
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
        fout[a[i]]+=d[i];fin[b[i]]+=d[i];
    }
    for (int i=1;i<=n;i++)
    {
        if (fin[i]>fout[i]) addedge(s,i,fin[i]-fout[i],0);
        else addedge(i,t,fout[i]-fin[i],0);
    }
    addedge(n,1,inf,0);
    for (int i=1;i<=m;i++)
    {
        if (d[i]>c[i])
        {
            addedge(a[i],b[i],inf,2);
            addedge(b[i],a[i],d[i]-c[i],0);
            addedge(b[i],a[i],c[i],1);
            ans+=d[i]-c[i];
        }
        else
        {
            addedge(a[i],b[i],c[i]-d[i],1);
            addedge(a[i],b[i],inf,2);
            addedge(b[i],a[i],d[i],1);
        }
    }
    while (spfa()) ans+=dinic();
    printf("%d\n",ans);
    return 0;
}

B.

  奇妙的数学题。

    首先for i=2 -> n是肯定的。考虑如何在log^2n的时间内得到答案。

有一个log^3n的做法是显然的。对于一个新的i,我们枚举它所有的质因数,加到一个数组里,那么这是我们的答案就是对于每个质因数的答案和上一个的答案取max(每一个质因数的答案:若2出现i次,则找到2出现次数大于i次的最小的那个n)。然后我们二分答案,通过[n/p]+[n/p^2]+[n/p^3]+....算出答案。

考虑如何优化(神来之笔)。将n看成p进制的数akak-1ak-2....a1a0。然后考虑上面那个式子的答案就是Σai*(p^i-1)/(p-1),且使上面那个式子刚好>=cnt。怎么确定数组a呢?直接贪心就好了!预处理后面关于p的多项式,之后能取大就取大。这样一定是正确的(但是我不知道为什么)。。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 1000050
#define mod 1000000007
using namespace std;
long long n,k,prime[maxn/5],tot=0,mn[maxn],ans=0,tab[maxn],kr=0,num[maxn];
bool vis[maxn];
void get_table()
{
    mn[1]=1;
    for (long long i=2;i<=maxn-50;i++)
    {
        if (!vis[i]) {vis[i]=true;prime[++tot]=i;mn[i]=i;}
        for (long long j=1;j<=tot && i*prime[j]<=maxn-50;j++)
        {
            vis[i*prime[j]]=true;mn[i*prime[j]]=prime[j];
            if (!i%prime[j]) break;
        }
    }
}
long long ask(long long x,long long cnt)
{
    if (x==-1) return 0;
    long long lim=1,ret=1,ans=0;tab[1]=1;
    while (tab[ret]<=cnt) tab[++ret]=tab[ret-1]*x+1LL;
    ret--;
    for (long long i=ret;i>=1;i--)
    {
        ans=ans*x+cnt/tab[i];
        cnt%=tab[i];
    }
    return ans*x;
}
int main()
{
    scanf("%lld%lld",&n,&k);
    get_table();
    for (long long i=2;i<=n;i++)
    {
        long long x=i,ret1=-1,cnt=0,rr;
        while (x!=1)
        {
            if (mn[x]!=ret1) {ans=max(ans,ask(ret1,num[ret1]*k));ret1=mn[x];}
            num[mn[x]]++;
            rr=mn[x];x/=mn[x];
        }
        ans=max(ans,ask(ret1,num[rr]*k));cnt=1;
        kr=(kr+ans)%mod;
    }
    printf("%lld\n",kr);
    return 0;
}

C.

  杜教筛神题。。。感觉先要学一学杜教筛的东西再来看。就没写啦。

时间: 2024-10-17 01:34:40

FR #1题解的相关文章

FR #10题解

好 蠢 啊 A. 标准分治.每次从分治区间中找到最大值的位置m,设f[l,r]为[l,r]的答案,那么f[l,r]=f[l,m-1]+f[m+1,r]+跨过m点的贡献. 然后枚举小的区间放到大的区间中查就行了.复杂度nlog^2n. TM的这5e5你给128M怎么回事...开6s又怎么回事... #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define

FR #11题解

A. 瞎jb折半dp一下,然后合并一下就好了. O2加成十分显著...6s变成0.9s... #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<bitset> #define maxv 100 #define maxe 20000 using namespace std; int n,m,d,x,y,z,g[maxv],nume=1

FR #12题解

A. 我的做法是nmlogn的....直接做m次堆贪心就可以.按理说是能过的... 正解直接是在原dp上搞一搞...可以做到n^2+nlog? 2333 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define maxn 2050 using namespace std; long long n,m,a[max

FR #2题解

A. 考虑把(u,v)的询问离线挂在u上,然后dfs,每次从fath[x]到[x]相当于x子树dis区间加1,x子树以外区间-1,然后维护区间和区间平方和等. 常数略大. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #define maxv 100500 #define maxe 200500 using na

bzoj 3519: [Zjoi2014] 消棋子 题解

[序言]在大家怀疑的眼光下,我做了一个中午和半个下午.调了一个晚上的题目总算A了! [原题] 消棋子是一个有趣的游戏.游戏在一个r * c的棋盘上进行.棋盘的每个格 子,要么是空,要么是一种颜色的棋子.同一种颜色的棋子恰好有两个.每一轮, 玩家可以选择一个空格子(x, y),并选择上下左右四个方向中的两个方向,如果 在这两个方向上均存在有棋子的格子,而且沿着这两个方向上第一个遇到的棋子 颜色相同,那么,我们将这两个棋子拿走,并称之为合法的操作.否则称这个操 作不合法,游戏不会处理这个操作.游戏的

东南大学第十三届程序设计竞赛初赛题解

问题 A: 天梯评分系统 题目描述 在一个下雨的日子,沈学姐和四个好基友约定无事一同打dota(dota是一个5对5的MOBA类游戏)因为想证明谁最NB,他们就全部注册新号去爬天梯了.天梯有一套完整的评分系统,它可以根据每位选手每局的数据进行评分,因为dota的英雄既有辅助又有ganker还有后期,所以不同的英雄的评分标准不一样.可惜那天天梯服务器维护,无法进行评分.于是,他们记录下每一局的数据,找你来帮忙,希望你能够帮他们仿照天梯编一个评分系统,以便于他们比较谁是真正的神牛. 已知对于每个账号

LeetCode: Roman to Interger 题解

Given a roman numeral, convert it to an integer. Input is guaranteed to be within the range from 1 to 3999. 找到规则即可 罗马数字的表示: I~1 V~5 X~10 L~50 C~100 D~500 M~1000 规则: 基本数字Ⅰ.X .C 中的任何一个,自身连用构成数目,或者放在大数的右边连用构成数目,都不能超过三个:放在大数的左边只能用一个. 不能把基本数字V .L .D 中的任何一

codeforces A. Shaass and Oskols 题解

Shaass has decided to hunt some birds. There are n horizontal electricity wires aligned parallel to each other. Wires are numbered 1 to n from top to bottom. On each wire there are some oskols sitting next to each other. Oskol is the name of a delici

2016 年宁波工程学院第七届ACM校赛题解报告

2016 年宁波工程学院第七届ACM校赛题解报告 本题解代码直接为比赛代码,仅供参考. A,B,C,D,G,H,J,K,L,M 来自 Ticsmtc 同学. F 来自 Gealo 同学. E,I 来自Alex 学长. Promblem A :    Two Sum 时间限制: 1 Sec  内存限制: 64 MB 题目描述: 给出n个数,另外给出?个整数S,判断是否可以从中取出2个数,使得这两个数的和是S. 输入: 第?行有个整数T(1 <= T <= 10),代表数据组数. 对于每组数据,第