• NOIP 模拟 1003


    天空龙

    奥西里斯有a 个红色,b 个黄色,c 个蓝色,他想用画出最好的画,可是需要至少x 个红色,y 个黄色和z 个蓝色,似乎并不够。别担心,奥西里斯会魔法!他可以把任何两个同种颜色转化为一个另一种颜色!请问他能不能完成呢?

    t<=100,0<=a,b,c,x,y,z<=1000000。

    题解

    稍微想一下就知道不存在拿对自己有用的去帮助别人,最后让别人帮自己,那么直接看多出来的能填多少空就行。

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    int t,a,b,c,x,y,z;
    
    int main(){
        freopen("osiris.in","r",stdin);
        freopen("osiris.out","w",stdout);
        scanf("%d",&t);
        while(t--){
            int tot=0,need=0;
            scanf("%d%d%d%d%d%d",&a,&b,&c,&x,&y,&z);
            if(a>x) tot+=(a-x)>>1;
            else need+=x-a;
            if(b>y) tot+=(b-y)>>1;
            else need+=y-b;
            if(c>z) tot+=(c-z)>>1;
            else need+=z-c;
            printf("%s
    ",tot>=need ? "YES" : "NO");
        }
    }
    /*
    3
    4 4 0 2 1 2
    5 6 1 2 7 2
    3 3 3 2 2 2
    */
    osiris

    巨神兵

    欧贝利斯克的巨神兵很喜欢有向图,有一天他找到了一张n 个点m 条边的有向图。

    欧贝利斯克认为一个没有环的有向图是优美的,请问这张图有多少个子图(即选定一个边集)是优美的?答案对1,000,000,007 取模。

    对于40%的数据n<=5,m<=20;

    对于60%的数据n<=10;

    对于80%的数据n<=15;

    对于100%的数据n<=17。

    题解

    40%的做法,就暴力枚举边集最后用拓扑判环。

    #include<ctime>
    #include<queue>
    #include<vector>
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int mod=1000000007;
    const int maxn=20;
    const int maxm=250;
    int n,m,ret;
    int cnt,du[maxn],d[maxn];
    vector<int> c[maxn];
    struct edge{
        int x,y;
    }e[maxm];
    
    template<class T>inline void read(T &x){
        x=0;int f=0;char ch=getchar();
        while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        x = f ? -x : x ;
    }
    
    int topsort(){
        queue<int> q;
        int tot=0;
        for(int i=1;i<=n;i++){
            d[i]=du[i];
            if(!du[i]) q.push(i),tot++;
        }
        while(!q.empty()){
            int x=q.front();
            q.pop();
            for(unsigned int i=0;i<c[x].size();i++){
                int y=c[x][i];
                if(d[y]){
                    d[y]--;
                    if(!d[y]) q.push(y),tot++;
                }
            }
        }
        return tot==n;
    }
    
    void dfs(int s){
        if(!topsort()) return ;
        if(s>m){
            ret++;
            if(ret>=mod) ret-=mod;
            return ;
      }
        dfs(s+1);
        du[e[s].y]++;
        c[e[s].x].push_back(e[s].y);
        dfs(s+1);
        c[e[s].x].pop_back();
        du[e[s].y]--;
    }
    
    int main(){
        freopen("obelisk.in","r",stdin);
        freopen("obelisk.out","w",stdout);
        read(n);read(m);
        for(int i=1;i<=m;i++) read(e[i].x),read(e[i].y);
        dfs(1);
        printf("%d",ret);
    }
    obelisk


    对于60%的数据,考虑把有向图分层(貌似是一种套路),分层就是类似topsort一样的,第一层是最初入度为0的点,去掉他们入度为0的是第二层....

    然后考虑f[i][j],i为现在选取的点集,j为最后一层的点集,考虑一个可以转移的点集k:满足与i无交集,k中每个点都与j有连边(和i其他点无所谓)

    考虑转移答案f[i|k]+=f[i][j]*num1,num1为选边的方案数,是每个k中的点选边方案数的乘积,k中点选边方案数是至少选一条连向j的边*选取连向i中其他点的边的方案数。

    #include<ctime>
    #include<queue>
    #include<vector>
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define ll long long
    const int mod=1000000007;
    const int maxn=100;
    const int maxm=250;
    int n,m,tot;
    int cnt,head[maxn];
    ll ret,pow2[maxn],f[1030][1030];
    struct edge{
        int x,y,next;
    }e[maxm];
    
    template<class T>inline void read(T &x){
        x=0;int f=0;char ch=getchar();
        while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        x = f ? -x : x ;
    }
    
    void add(int x,int y){
        e[++cnt]=(edge){x,y,head[x]};
        head[x]=cnt;
    }
    
    bool get(int x,int s){return (1<<(x-1))&s;}
    
    int main(){
        freopen("obelisk.in","r",stdin);
        freopen("obelisk.out","w",stdout);
        read(n);read(m);
        pow2[0]=1;
        for(int i=1;i<=m;i++) pow2[i]=pow2[i-1]*2;
        for(int i=1;i<=m;i++){
            int x,y;
            read(x);read(y);
            add(y,x);
        }
        tot=(1<<n)-1;
        for(int i=1;i<=tot;i++) f[i][i]=1;
        for(int i=1;i<=tot;i++)//总共选的点 
            for(int j=i;j;j=(j-1)&i){//最后一层,是i的子集
            if(!f[i][j]) continue;
                int cx=tot^i;//i的补集,k的选取集合 
                for(int k=cx;k;k=(k-1)&cx){
                    ll num1=1;
                    for(int o=1;o<=n;o++){
                        if(!get(o,k)) continue;//找出k里面的节点
                        ll cnt1=0,cnt2=0;//连向j的边,连向i中除了j的边 
                        for(int l=head[o];l;l=e[l].next){
                            int y=e[l].y;
                            if(get(y,j)) cnt1++;
                            else if(get(y,i)) cnt2++;
                        }
                        num1=num1*(pow2[cnt1]-1)%mod;//必须选一个 
                        num1=num1*pow2[cnt2]%mod;
                        if(!num1) break;//只能是与j无连边 
                    }
                    if(!num1) continue;
                    f[i|k][k]=(f[i|k][k]+f[i][j]*num1%mod)%mod;
                }
            }
        for(int i=1;i<=tot;i++) ret=(ret+f[tot][i])%mod;
        printf("%d",ret);
    }
    60

    对于100%的数据,考虑不要第二维,会统计重复所以加个容斥(我也不知道为啥容斥是这样)

    具体看代码吧,理解到上面的就差不多可以理解了(除了容斥)

    #include<ctime>
    #include<queue>
    #include<vector>
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define ll long long
    const int mod=1000000007;
    const int maxn=20;
    const int maxm=250;
    int n,m,tot;
    int mp[maxn][maxn];
    ll pow2[maxm],f[1<<17];
    ll a[1<<17],b[1<<17];//边数 
    int num[1<<17];//容斥系数,按二进制下1的个数 
    
    template<class T>inline void read(T &x){
        x=0;int f=0;char ch=getchar();
        while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        x = f ? -x : x ;
    }
    
    bool get(int x,int s){return (1<<(x-1))&s;}
    
    int main(){
        freopen("obelisk.in","r",stdin);
        freopen("obelisk.out","w",stdout);
        read(n);read(m);
        pow2[0]=1;
        for(int i=1;i<=m;i++) pow2[i]=pow2[i-1]*2%mod;
        for(int i=1;i<=m;i++){
            int x,y;
            read(x);read(y);
            mp[x-1][y-1]=1;
        }
        tot=(1<<n)-1;
        num[0]=-1;
        for(int i=1;i<=tot;i++) num[i]=num[i>>1]*( i&1 ? -1 : 1 );
        f[0]=1;
        for(int i=0;i<tot;i++){
            for(int j=0;j<n;j++) b[1<<j]=0;
            for(int j=0;j<n;j++)
             if((1<<j)&i)
              for(int k=0;k<n;k++)
               b[1<<k]+=mp[j][k];
            a[0]=0;
            int j=tot^i;
            for(int k=(j-1)&j;;k=(k-1)&j){
                int now=j^k,o=now&-now;//为了从小到大枚举
                a[now]=a[now^o]+b[o];
                f[i|now]=(f[i|now]+f[i]*pow2[a[now]]*num[now])%mod;
                if(!k) break;
            }
        }
        printf("%d",(f[tot]+mod)%mod);
    }
    100

    太阳神

    太阳神拉很喜欢最小公倍数,有一天他想到了一个关于最小公倍数的题目。

    求满足如下条件的数对(a,b)对数:a,b 均为正整数且a,b<=n 而lcm(a,b)>n。其中的lcm 当然表示最小公倍数。答案对1,000,000,007取模

    对于100%的数据n<=10000000000。

    题解

    不会数论,只有照着别人说

    有杜教筛啥的,不过我这就讲我理解得到的

    补集转换(顶不住)

    那么就考虑lcm(i,j)<=n的

    $sum_{i=1}^{n}sum_{j=1}^{n}[gcd(i,j)leq n]$

    $sum_{k}sum_{i=1}^{n}sum_{j=1}^{n}[gcd(frac{i}{k},frac{j}{k})=1][frac{ij}{k}leq n]$

    $sum_{k}sum_{i=1}^{n}sum_{j=1}^{n}sum_{d|gcd(frac{i}{k},frac{j}{k})}mu (d)[frac{ij}{k}leq n]$

    $sum_{k}mu (d)sum_{d|frac{i}{k}}^{n}sum_{d|frac{j}{k}}^{n}[frac{ij}{k}leq n]$

    $sum_{k}mu (d)[frac{ij}{k}leq frac{n}{d^2}]$

    $mu (d)sum_{k}[frac{i}{k}frac{j}{k}kleq frac{n}{d^2}]$

    $frac{n}{d^2}geq 1, herefore dleq sqrt n$

    所以考虑枚举d,找出符合的$frac{i}{k},frac{j}{k},k$

    $假设frac{i}{k}leq frac{j}{k}leq k$

    $frac{i}{k}leq sqrt[3]{frac{n}{d^2}},frac{j}{k}*frac{j}{k}leqfrac{n}{d^2i}$

    所以就枚举前两个可以得到k的范围,就知道满足条件的有多少个了,然后考虑三者可以互换(因为本身没有大小关系),分类讨论一下即可。

    最后答案是n*n-求出的答案

    #include<cmath>
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define ll long long
    const int mod=1000000007;
    const int maxn=100000;
    ll n,m,ans;
    int prime[maxn+5],mu[maxn+5];
    bool not_prime[maxn+5];
    
    void init(){
        mu[1]=1;
        for(int i=2;i<=maxn;i++){
            if(!not_prime[i]){
                prime[++prime[0]]=i;
                mu[i]=-1;
            }
            for(int j=1;j<=prime[0]&&i*prime[j]<=maxn;j++){
                not_prime[i*prime[j]]=true;
                if(i%prime[j]) mu[i*prime[j]]=-mu[i];
                else {
                    mu[i*prime[j]]=0;
                    break;
                }
            }
        }
    }
    
    int main(){
        freopen("ra.in","r",stdin);
        freopen("ra.out","w",stdout);
        scanf("%lld",&n);
        init();
        m=sqrt(n+0.5);
        for(int d=1;d<=m;d++){
            ll val=n/d/d,ret=0;
            for(ll i=1;i*i*i<=val;i++)
             for(ll j=i;j*j<=val/i;j++){
                  ll c=val/i/j-j+1;
                  //i*j*k<=val,i<=j<=k
                  //c:k的取值个数
                  if(i==j) ret=(ret+1+(c-1)*3)%mod;//1:j==k,否则i,j,k有三种排列
                 else ret=(ret+3+(c-1)*6)%mod; 
             }
            ans=(ans+mu[d]*ret)%mod;
        }
        ans=(n%mod)*(n%mod)%mod-ans;
        ans=(ans%mod+mod)%mod;
        printf("%lld",ans);
    }
    ra
  • 相关阅读:
    [转载]链接 构造最全的java面试题整理
    [转载]面试技巧问题:面试典型问题回答技巧
    [转载]工作面试时最难的25个问题
    [转载][转]tomcat server.xml配置详解
    [转载]链接 构造最全的java面试题整理
    [转载]转 构造最全的java面试题整理(线程篇)
    [转载]C++ 面试
    [转载]转 构造最全的java面试题整理(线程篇)
    [转载][转]tomcat server.xml配置详解
    [转载]面试技巧问题:面试典型问题回答技巧
  • 原文地址:https://www.cnblogs.com/sto324/p/11620673.html
Copyright © 2020-2023  润新知