少年,你渴望力量吗(20190831)?

今日份考试,手动滑稽

 

一、FFF团

【题目描述】

从前,Shylock和Lucar 幸福的生活在一起。

在情人节前夕,他们出去逛街,遇到了FFF团的成员集体活动,于是他们就被FFF团抓进了地牢,并把他们关进了随机的两个不同的房间里。FFF团的团长打算明天将他们淹没在火海之中。但是团长给了他们一个机会,如果他们其中一个人能到达另一个人的房间(另一个人不动),那么就放过他们,否则就关到第二天然后点火。

地牢里面有n个房间,m条路,每一条路连接两个房间,并且路是有方向的。

现在问Shylock和Lucar是否无论在任何情况下,都满足他们其中一个人能到达另一个人的房间,如果是则输出“I love you my love and our love save us!”,否则输出“Light my fire!”

【输入格式】

本题包含多组数据。

对于每组数据,第一行输入T,表示数据组数。

下面一行两个整数n,m,分别表示房间数和路的数量。

接下来的m行,每行两个整数x,y,表示从第x个房间有一条路可以到达y房间。

每组数据后有一个空行。

【输出格式】

输出一行,如果问Shylock和Lucar是否无论在任何情况下,都满足他们其中一个人能到达另一个人的房间,如果是则输出“I love you my love and our love save us!”,否则输出“Light my fire!”


一波强连通缩点,再来个拓扑排序

非常美妙,令人极度舒适

#include<bits/stdc++.h>
#define re return
#define inc(i,l,r) for(int i=l;i<=r;++i)

using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}

const int maxn=20005,maxm=200005;
int T,n,m,k,hd[maxn],dfn[maxn],low[maxn],belong[maxn];
int tot,col,fr[maxn],to[maxn],fa[maxn],d[maxn];
struct node{
    int fr,to,nt;
}e[maxm];

inline void add(int x,int y)
{
    e[++k].to=y;e[k].nt=hd[x];hd[x]=k;e[k].fr=x;
}

stack<int>s;

inline void tarjan(int x)
{
    s.push(x);
    dfn[x]=low[x]=++tot;
    for(int i=hd[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[x]=min(low[x],low[v]);
        }
        else if(!belong[v])
            low[x]=min(low[x],dfn[v]);
    }
    
    if(dfn[x]==low[x])
    {
        ++col;
        int v=-1;
        while(v!=x)
        {
            v=s.top();
            s.pop();
            belong[v]=col;
        }
    }
}

inline int find(int x)
{
    re x==fa[x]?x:fa[x]=find(fa[x]);
}

inline bool topo()
{
    int cnt=0;
    k=0;
    inc(i,1,col)hd[i]=0;
        
    inc(i,1,m)
    {
        int x=belong[e[i].fr];
        int y=belong[e[i].to];
        if(x!=y)
        {
            add(x,y);
            ++d[y];
        }
    }
    
    queue<int>q;    
    inc(i,1,col)if(!d[i])
    {
        ++cnt;
        q.push(i);
    }
    
    while(!q.empty())
    {
        if(cnt>1)re 1;
        int u=q.front();
        --cnt;
        q.pop();
        for(int i=hd[u];i;i=e[i].nt)
        {
            int v=e[i].to;
            --d[v];
            if(!d[v])
            {
                ++cnt;
                q.push(v);
            }
        }
    }
    re 0;    
}

int main()
{
    
    //freopen("in.txt","r",stdin);
    rd(T);
    while(T--)
    {
        rd(n),rd(m);
        k=tot=col=0;
        inc(i,1,n)
        {
            dfn[i]=low[i]=belong[i]=0;
            d[i]=to[i]=fr[i]=hd[i]=0;
            fa[i]=i;    
        }
        
        int x,y;
        inc(i,1,m)
        {
            rd(x),rd(y);
            add(x,y);
        }
        
        
        inc(i,1,n)
        if(!dfn[i])
            tarjan(i);
        
        
        if(topo())printf("Light my fire!\n");
        else printf("I love you my love and our love save us!\n");
    }
    re 0;
} 

二、maple做数学题

【题目描述】

有一天,maple上数学课,他学会了如何求一个数的因子,于是老师给他布置了一道题,在区间[L,R]里面,找出所有满足下列条件的数字:这个数的第二小的因子为K。找到这些数字以后,maple还要去把这些数加起来,请问最终结果是什么?

【输入格式】

输入数据只有一行,三个数字L,R,K含义如题目描述所示

【输出格式】

一个整数,表示把这些数加起来的和是多少,答案模 mod1e9+7 mod1e9+7

【输入样例1】

1 20 5

【输出样例1】

5

【输入样例2】

2 6 3

【输出样例2】

3

【数据约定】

20%的数据1LR10^5 ,2K10^5 1≤L≤R≤10^5,2≤K≤10^5

100%的数据1LR10^11 ,2K10^11 1≤L≤R≤10^11,2≤K≤10^11


像我这样的数学渣:

咦,数学诶!

思考1min……

不可做,绝对不可做

看了看第三题,又是一道古拉拉级膜法题:数学

暴力,暴力~~~

爆零,爆零~~~

然而坚强的LL成功苟到60pts(鲜花,掌声)

正解(dp)

#include<bits/stdc++.h>
#define re return
#define ll long long
#define inc(i,l,r) for(int i=l;i<=r;++i)

using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}

const int maxn=16000005,NN=10010,MM=120;
const ll mod=1e9+7;

ll L,R,K,dp[NN][MM];
ll cnt,notprime[320005],prime[320005];

inline bool isprime(ll x)
{
    if(x%2==0&&x!=2)re 0;
    for(int i=3;i<=sqrt(x);i+=2)
    if(!(x%i))re 0;
    re 1;
}

inline void Get_prime()//得到质数 
{
    notprime[1]=1;
    inc(i,2,K)
    {
        if(!notprime[i])
        prime[++cnt]=i;
        
        inc(j,1,cnt)
        {
            if(prime[j]*i>K)break;
            notprime[prime[j]*i]=prime[j];
            if(!(i%prime[j]))break;
        }
    }
}


inline ll F(ll n,ll m)
//F(n,m)表示前i个数,去掉前m个质数的和 
{
    ll ans;
    if(n<NN&&m<MM&&dp[n][m])re dp[n][m];//记忆化 
    else if(n<2)ans=n;//0,1不是任何质数的正整数级倍数 
    else if(!m) ans=((1+n)%mod)*(n%mod)%mod*500000004%mod;
    //即求前n个数的和,等差数列
    //因为除法取模不成立,所以转化为乘其(2)逆元(500000004) 
    else if(prime[m]>n)
    {
        while(m&&prime[m]>n)--m;
        //prime[m]>n无意义
        //简化 
        ans=F(n,m);
    }
    else ans=(F(n,m-1)-prime[m]*F(n/prime[m],m-1)%mod+mod)%mod;
    //重点 :对于(n/prime[m]),比如说5,5的2倍,以及5的3倍都是不成立的 
    if(n<NN&&m<MM)dp[n][m]=ans;//记忆化 
    re ans;
}

int main()
{
    rd(L),rd(R),rd(K);
    
    if(!isprime(K))printf("0");
    //如果K不是素数,则其倍数次小因子绝对不是K 
    else if(sqrt(R)<K)
    {
    //当K在1~R中最多只能苟一个即(K)时 
        if(R>=K&&K>=L)printf("%lld",K%mod);
        else printf("0");
    }
    else 
    {
        Get_prime();//得到小于K的所有质数 
        printf("%lld",(F(R/K,cnt-1)*K%mod-F((L-1)/K,cnt-1)*K%mod+mod)%mod);
    }

    re 0;
} 

三、数字

【题目描述】

有一个n个数字的列表,你可以对列表进行两种操作

1.用x的代价删除一个数字

2.用y的代价选择一个数字增加1

两种操作没有次数限制,问使得这个列表所有数字的gcd(最大公因数)大于1的最少花费是多少?

【输入格式】

第一行三个整数表示n、x、y。

第二行有n个整数表示这个列表的数字。

【输出格式】

一个整数表示最少花费。

【输入样例1】

4 23 17
1 17 17 16

【输出样例1】

40

【输入样例2】

10 6 2
100 49 71 73 66 96 8 60 41 63

【输出样例2】

10

【数据约定】

对于30%数据 1<=n<=1000

对于100%数据 1<=n<=500000 ,1<=x,y<=1000000000, 1<=a[i]<=1000000


突然明白为什么今天早上我错了……

其实由于数据过水,gcd只用枚举50以内

悲伤,雨中肖邦

骗分大法

#include<bits/stdc++.h>
#define re return
#define ll long long
#define inc(i,l,r) for(register int i=l;i<=r;++i)

using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}

int prime[100005],notprime[1000005];
int n,maxx,cnt,a[500005];

inline void Get_prime()
{
    notprime[1]=1;
    inc(i,2,50)
    {
        if(!notprime[i])
        prime[++cnt]=i;
        inc(j,1,cnt)
        {
            if(prime[j]*i>50)break;
            notprime[prime[j]*i]=prime[j];
            if(i%prime[j])break;
        }
    }
}

int main()
{
    int cx,cy;
    rd(n),rd(cx),rd(cy);
    
    inc(i,1,n)
    {
        rd(a[i]);
        maxx=a[i]>maxx?a[i]:maxx;
    }
    
    ll ans=99999999999999999;
    Get_prime();//获得50以内的质因数
    inc(c,1,15)//共有16个
    {
        int i=prime[c];
        ll nowans=0;
        inc(j,1,n)
        {
            ll t=a[j]%i;
                if(t)t=(i-t)*(ll)cy;//要成为i的倍数至少还要i-t;
                        //需要cy*(i-t)费用
                nowans+=cx<t?cx:t;//比较取最小
            if(nowans>ans)break;//剪枝
        }
        ans=ans<nowans?ans:nowans;
    }
    //暴力枚举
    printf("%lld",ans); 
    re 0;
} 
    

猜你喜欢

转载自www.cnblogs.com/lsyyy/p/11440362.html