今天翻车了,挂分挂了90(测试大样例忘记删freopen了)直接rank3  -->rank21,考得真烂

以后每次考前看一次考前注意;

T1工业题/a

这个题其实挺简单的

f[ i ][ 0 ]每个点对ans的贡献就是f[ i ]*C(n+m-1-i,m-1)*a^(m)*b^(n-i);

f[ 0 ][ i ]每个点对ans的贡献就是f[ i ]*C(n+m-1-i,n-1)*a^(m-i)*b^(n);

组合数就是道路条数,也就是这个数出现的次数

记得输入a和b的时候%mod,否则在处理的时候会爆longlong,因为这挂了10分

还有,记得删掉freopen!!!!!!!!!!因为这又挂了90

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{    
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
        f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
int n,m,a,b;
const long long mod=998244353;
const int maxn=3e5+1;
int jc[maxn*3],ni[maxn*3];
int aj[maxn*3],bj[maxn*3];
int fi[maxn*3],fj[maxn*3];
inline int C(int x,int y)
{
    return ((jc[x]*ni[y]%mod)*ni[x-y])%mod;
}
inline int ksm(int j,int k)
{
    int f=1;
    j=j%mod;
    while(k>0)
    {
        if(k%2==1)
        {
            f=(f*j)%mod;
        }
        k*=0.5;
        j=(j*j)%mod;
    }
    return f;
}
signed main()
{
    int ans=0;
    n=read(),m=read(),a=read()%mod,b=read()%mod;
    jc[0]=1;
    aj[0]=1;
    bj[0]=1;
    ni[0]=1;
    for(int i=1;i<=n+m;i++)
    jc[i]=(jc[i-1]*i)%mod,aj[i]=(aj[i-1]*a)%mod,bj[i]=(bj[i-1]*b)%mod;
    ni[n+m]=ksm(jc[n+m],mod-2);
    for(int i=n+m-1;i>=0;i--)
    ni[i]=(ni[i+1]*(i+1))%mod;
    for(int i=1;i<=n;i++)
    fi[i]=read()%mod,ans=(ans+((((fi[i]*C(n-i+m-1,m-1)%mod)%mod)*aj[m])%mod)*bj[n-i])%mod;
    for(int i=1;i<=m;i++)
    fj[i]=read()%mod,ans=(ans+((((fj[i]*C(n-i+m-1,n-1)%mod)%mod)*aj[m-i])%mod)*bj[n])%mod;
    cout<<ans;    
}
T1

T2卡常题/b

这题第一眼看就不可做,打了个二十分状压直接走人了;

这个题看着题面特别高大上,什么二分图之类的,根本看不懂,但看了题解还是挺好理解的

首先,两个x之间夹着一个y,那么我们可以把x点看作点,把y点看作边,不考虑边权;

我们把激活x所需要的权值记为点权,那么这个题也就变成了每条边至少有一个点是激活的最少权值

然后我们在看,n条边,n个点,那么这肯定是有一个环的,貌似这种图叫做什么基环树,不懂,说白了就是有一个环的树

那么我们要考虑破环为链,我们可以找环上的一条边,把他断掉,然后以这条边的两个端点为根分别跑树形dp

这两个点至少要有一个是激活的,那么最终的答案就是第一个点激活情况下的最小值和第二个点激活情况下的最小值之间的最小值

我们定义dp[ i ][ 1 ]是选i的最少情况,dp[ i ][ 2 ]是不选i的最少情况

如果i被激活,那么儿子激活不激活都没事,取一个最小值就行了,如果i没有被激活,那么他的儿子都要激活

我们考率如果进行删边,我们只要在dfs的时候判断一下就好了,假如要搜的这个点曾经搜到过,并且这个点不是当前点的上一个点

那么这一条边肯定在环上,那么就取当前点和这个点做两个根,就好了

然后再分别以两个点为根跑dfs,用vector存儿子,跑dp就好了

#include<bits/stdc++.h>
using namespace std;
inline int read()
{    
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
        f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
const int maxn=1e6+5;
int n,a,b,tot;
int head[maxn],gen1,gen2,to[maxn*2],ans1,ans2,nxt[maxn*2],val[maxn],dp[maxn][3];
vector<int >q[maxn][2];
bool vis[maxn];
inline int min(int x,int y){return x<y?x:y;}
inline int max(int x,int y){return x>y?x:y;}
inline void swap(int &x,int &y){x^=y^=x^=y;}
inline int abs(int x){return x<0?-x:x;}
inline void add(int x,int y)
{
    to[++tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
    swap(x,y);
    to[++tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
}
void dfs(int x,int f)
{
    vis[x]=1;
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];
        if(vis[y]&&y!=f)
        {
            gen1=x,gen2=y;
            continue;            
        }
        if(vis[y]||y==f)
        continue;
        dfs(y,x);
    }
}
void dfs1(int x,int fa,int f)
{
    q[fa][f].push_back(x);
    vis[x]=1;
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];
        if((x==gen1&&y==gen2)||(y==gen1&&x==gen2))
        continue;
        if(vis[y]||y==fa)
        continue;
        dfs1(y,x,f);
    }
}
void solve(int x,int f)
{
    dp[x][1]=val[x];
    dp[x][2]=0;
    if(q[x][f].size()==0)
    {
        return ;
    }
    for(int i=0;i<q[x][f].size();i++)
    {
        int y=q[x][f][i];
        solve(y,f);
        dp[x][1]+=min(dp[y][2],dp[y][1]);
            dp[x][2]+=dp[y][1];        
    }
}
int main()
{
    n=read(),a=read(),b=read();
    int x,y;
    for(int i=1;i<=n;i++)
    {
        x=read(),y=read();
        add(x,y);
        val[x]+=a,val[y]+=b;
    }
    dfs(1,0);
    memset(vis,0,sizeof(vis));
    dfs1(gen1,0,0);
    solve(gen1,0);
    ans1=dp[gen1][1];
    memset(vis,0,sizeof(vis));
    dfs1(gen2,0,1);
    solve(gen2,1);
    ans2=dp[gen2][1];
    cout<<min(ans1,ans2);
}
T2

T3玄学题/c

吓死了,差点以为又是概率和期望的题,我这方面最垃圾了。。。

题意很简单,我们就考虑奇偶性就好了,当且仅当里面这个数是完全平方数的时候,才会是奇数

那么问题就是如何判断是不是完全平方数了

首先,我们可以把x拆成p×q^2,如果说y×x是一个完全平方数的话,y肯定存在p×z^2的形式,

那么我们就可以找m/p[ i ]里面有多少个完全平方数,如果有奇数个就--,偶数个就++

我用的找p的方法是一种比较垃圾的筛法,开longlong只有50分,不开还能呢个有70呢。。。。

后来改成了小B(zxb)筛法,O(n)就能筛掉了,其实就是反过来了;

#include<bits/stdc++.h>
using namespace std;
inline int read()
{    
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
        f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
int n,m;
const int maxn=1e7+1;
int ans=0,a[maxn];
signed main()
{
    n=read(),m=read();
    int q=sqrt(n);
    for(int i=1;i<=n;i++) a[i]=i;
    for(int i=q;i>=2;i--)
    {
        int now=i*i;
        for(int j=now;j<=n;j+=now)
        {
            if(a[j]%now==0)
            {
                while(a[j]%now==0)
                a[j]/=now;
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        int now=m/a[i];
        now=sqrt(now);
        if(now&1)
        --ans;
        else
        ++ans;
    }
    cout<<ans;
}
70
#include<bits/stdc++.h>
#define ll long long
#define int long long
using namespace std;
inline int read()
{    
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
        f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
ll n,m;
const int maxn=1e7+1;
ll ans=0,a[maxn];
bool b[maxn*2];
int cf[maxn*2],cnt;
signed main()
{
    n=read(),m=read();
    int q=sqrt(n);
    for(int i=2;i<=sqrt(n)+1;i++) 
    cf[++cnt]=i*i,b[i*i]=1;
    for(int i=1;i<=cnt;i++)
    for(int j=1;j*cf[i]<=n;j++)
    if(!b[j])
    a[j*cf[i]]=j;
    for(int i=1;i<=n;i++)
    {
        if(!a[i]) a[i]=i;
        ll now=m/a[i];
        now=sqrt(now);
        if(now&1)
        --ans;
        else
        ++ans;
    }
    for(int i=1;i<=n;i++)
    cout<<a[i]<<endl;
    cout<<ans;
}
AC

 

posted on 2021-07-13 17:08  JYFHYX  阅读(34)  评论(0编辑  收藏  举报