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\n",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

太阳神

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

求满足如下条件的数对(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}k\leq \frac{n}{d^2}]$

$\frac{n}{d^2}\geq 1,\therefore d\leq \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}\leq\frac{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

猜你喜欢

转载自www.cnblogs.com/sto324/p/11620673.html