2019年7月29日(NOIP模拟赛DAY1)

\(fake\)的题目!!

prob1:Alice和Bob的游戏(game)

题目大意:给一个数,可把他换成非其本身与一的任一因数,当一方无法换时则该方获胜,\(Alice\)先手,输出谁获胜

第一次碰见这么仁慈的学长,竟然送分送的这么到位,好评!!

shabi思路,\(Bob\)能获胜当且仅当该数有两个质因子,如此判断即可。

贴代码:

#include<iostream>
#include<cstdio>
using namespace std;
#define in read()
#define fur(i,a,b) for(ll i=a;i<=b;++i)
#define ll long long
#define xx 1100000
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
ll yin[xx],sus[xx],all=0;
bool su[xx];
int main()
{
    fur(i,2,1e6+10)
    {
        if(!su[i])
        {
            sus[++all]=i;
            for(ll j=2;j*i<=1e6+10;++j) su[j*i]=true;
        }
    }
    ll t=in;
    while(t--)
    {
        ll n=in,us=0;
        fur(i,1,all)
        {
            if(n<sus[i]) break;
            while(n%sus[i]==0)
            {
                us++;
                n/=sus[i];
            }
            if(us>=3) break;
        }
        if(n!=1) us++;
        if(us==2) puts("Bob");
        else puts("Alice");
    }
    return 0;
}

prob2:灭鲲(kun)

题目大意:有\(n\)个目标,分别有一个达成难度\(a_i\),有\(m\)种方式完成,代价\(c_j\),有效度\(d_j\),一种方式能完成一个目标当且仅当\(d_j>=a_i\),求完成所有目标的最小代价

30分DP:对目标与方式直接按难度与有效度排序,然后套\(01\)背包,可以证明这样是正确且最优的,时间复杂度\(O(n^2)\)\(1e6\)炸掉QWQ:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define fdr(i,a,b) for(int i=a;i>=b;--i)
#define int long long
const int inf=1e17+10;
const int xx=1e6+10;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
int f[xx],a[xx];
struct man{int d,c;}b[xx];
inline bool cmp(man x,man y){return x.d<y.d;}
signed main()
{
    int n=in,m=in;
    fur(i,1,n) a[i]=in;
    fur(i,1,m) b[i].d=in,b[i].c=in;
    sort(a+1,a+n+1);
    sort(b+1,b+m+1,cmp);
    memset(f,0x7f,sizeof(f));f[0]=0;
    fur(j,1,m) fdr(i,n,1) if(b[j].d>=a[i]) f[i]=min(f[i],f[i-1]+b[j].c);
    if(f[n]<inf) printf("%lld\n",f[n]);
    else puts("JiNiTaiMei!");
    return 0;
}

正解:将方式以\(c_j\)为关键词进行排序(桶排),将\(d_j\)用邻接表模拟链表挂在后面,用并查集将\(i\)指向小于等于\(i\)的最近\(a_i\)然后跑贪心,可以证明复杂度与正确性:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;i++)
#define int long long
const int xx=1e6+10;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
int a,c,d[xx];
int head[xx],nxt[xx],need[xx],fa[xx];
inline int find(int i){return (fa[i]==i)?i:(fa[i]=find(fa[i]));}
inline void add(int b,int e){nxt[e]=head[b];head[b]=e;}
signed main()
{
    int n=in,m=in,mxa=0,mxc=0,ans=0;
    fur(i,1,n)
    {
        a=in;
        need[a]++;
        mxa=max(mxa,a);
    }
    fur(i,0,mxa)
    {
        if(need[i]) fa[i]=i;
        else fa[i]=find(i-1);
    }
    fur(i,1,m)
    {
        d[i]=in;c=in;
        if(d[i]>mxa) d[i]=mxa;
        add(c,i);
        mxc=max(mxc,c);
    }
    fur(i,0,mxc)
    {
        for(int j=head[i];j;j=nxt[j])
        {
            int p=find(d[j]);
            if(!p) continue;
            need[p]--;n--;ans+=i;
            if(!need[p]) fa[p]=find(p-1);
            if(!n)
            {
                printf("%lld\n",ans);
                return 0;
            }
        }
    }
    puts("JiNiTaiMei!");
    return 0;
}

prob3:运河计划(canal)

题目大意:今天的考试日期去找吧(感性理解)

数学,容斥,行列式,高斯消元

时间不够了,题解上很清楚,大不了对代码再看一遍,

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define fdr(i,a,b) for(int i=a;i>=b;--i)
#define int long long
const int mod=998244353;
const int xx=200010;
const int yy=210;
inline int read()
{
    int x=0;
    char ch=getchar();
    for(;!isalnum(ch);ch=getchar());
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x;
}
int n,m,p,q;
int jc[xx],ny[xx],ab[yy][yy];
int f[yy],A[yy],B[yy];
struct point{int x,y;}dot[yy];
inline bool cmp(point a,point b){return (a.x^b.x)?(a.x<b.x):(a.y<b.y);}
inline int C(int mm,int nn){return nn>=mm?jc[nn]*ny[nn-mm]%mod*ny[mm]%mod:0;}
inline int power(int i,int k){int res=1;for(;k;k>>=1,i=i*i%mod) if(k&1) res=res*i%mod;return res;}
inline void init()
{
    jc[0]=ny[0]=ny[1]=1;
    fur(i,2,n+m) ny[i]=(mod-ny[mod%i]*(mod/i)%mod)%mod;
    fur(i,1,n+m) ny[i]=ny[i]*ny[i-1]%mod,jc[i]=jc[i-1]*i%mod;
}
inline void handle()
{
    fur(i,1,p)
    {
        fur(j,1,q) f[j]=A[i]<=dot[j].x?C(dot[j].y,dot[j].x-A[i]+dot[j].y):0;
        fur(j,1,q) fur(k,1,j-1)
        {
            if(dot[j].y<dot[k].y||dot[j].x<dot[k].x) continue;
            f[j]=(f[j]-f[k]*C(dot[j].y-dot[k].y,dot[j].x-dot[k].x+dot[j].y-dot[k].y)%mod+mod)%mod;
        }
        fdr(j,p,1)
        {
            if(B[j]<A[i]) break;
            ab[i][j]=C(n,n+B[j]-A[i]);
            fur(k,1,q)
            {
                if(dot[k].x>B[j]) continue;
                ab[i][j]=(ab[i][j]-f[k]*C(n-dot[k].y,n-dot[k].y+B[j]-dot[k].x)%mod+mod)%mod;
            }
        }
    }
}
inline void sol()
{
    int ans=1;
    fur(i,1,p)
    {
        fur(j,i+1,p)
        {
            while(ab[j][i])
            {
                int tmp=ab[i][i]*power(ab[j][i],mod-2)%mod;
                fur(k,i,p) ab[i][k]=(ab[i][k]-ab[j][k]*tmp%mod+mod)%mod,swap(ab[i][k],ab[j][k]);
                ans=(mod-ans)%mod;
            }
        }
        ans=ans*ab[i][i]%mod;
        if(!ab[i][i]) break;
    }
    printf("%lld\n",ans);
}
signed main()
{
    n=in;m=in;p=in;q=in;
    fur(i,1,p) A[i]=in;sort(A+1,A+p+1);
    fur(i,1,p) B[i]=in;sort(B+1,B+p+1);
    fur(i,1,q) dot[i].y=in,dot[i].x=in;sort(dot+1,dot+q+1,cmp);
    init();
    handle();
    sol();
    return 0;
}

\(ps\):线性求逆元要熟记!!!!!!!

猜你喜欢

转载自www.cnblogs.com/ALANALLEN21LOVE28/p/11312994.html
今日推荐