2018 hdu 多校 6

全世界都会莫比乌斯反演系列……
补题进度[3/12] 场上2题
1001 oval-and-rectangle
先把式子写出来,然后强行手算积分,最后把结果一输出就行了……不知道出题人出这个题的意图是什么。

1012 Pinball
由于不会各种牛逼的坐标系建系方法,所以采用了最原始的受力分解+运动分解。公式都写在代码里了
核心思想就是我们把速度和重力按照方向分解,发现可以分解成沿斜面的运动和在斜面上的平抛运动,答案就等于在运动到终点的时候,能进行平抛多少次。

#include <algorithm>
#include <iostream>
#include<bits/stdc++.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define INF 0x3f3f3f3f
#define G 9.8
using namespace std;
const double pi = acos(-1);
int main()
{
    int T;
    double b,a,x,y;
    cin>>T;
    while(T--)
    {
        cin>>a>>b>>x>>y;
        double th = atan(b/a);
        //cout<<th<<endl;
        //th *= pi;
        x = -x;
        double ay = G*cos(th);
        double ax = G*sin(th);
        //cout<<ax<<' '<<ay<<endl;
        double L  = x / cos(th);
        double h  = y - (b/a)*x;
        //cout<<L<<' '<<h<<endl;
        double v0 = sqrt(2*G*h);
        double vt = sin(th)*v0;
        double vh = cos(th)*v0;
        double t = 2*(vh/ay);
        //double l = t*vt;
        double T  = (sqrt(2*ax*L + vt*vt)-vt)/ax;
        //cout<<v0<<' '<<vh<<' '<<vt<<endl;
        //cout<<T<<' '<<t<<endl;
        cout<<floor(T/t) + 1<<endl;
    }

    return 0;
}

1007 Werewolf
提议就是简化版的狼人杀,只有狼人和村民两个角色。狼人可能说谎,村民一定说实话。问肯定是村民或者肯定是狼人的人数有多少个。
既然狼人可能说谎的话,那么所有的人都有可能是狼人,也就是说我们根本无法确定有多少人是村民。答案1就是0
那我们将方向集中在确定哪些人是狼。我们把一个人说另一个人的身份这个关系当成一个边,然后我们先把村民边(A说B是村民)建立反向边,然后里用并查集找狼人边是否成环,记录下成环的这个点,之后跑一边bfs,沿着反向边,将所有人都放进队列。最后的答案就是有多少个人被标记了,或者可以记录有多少个人入队。
为什么这样做呢。我们首先不考虑狼人边,如果一条村民边形成的链:A-B-C-D,现在D说B是狼,那么假如A是村民,也就是说BCD都是村民,但是D说B是狼,所以可以确认的是B肯定不是村民,因为以他和其之后的村民链是矛盾的。此时A知道B是狼,但是他说谎了,所以他也一定是不是村民。这就是为什么要建反向边的理由,因为这个节点反向边形成的子树全部都肯定是狼,因为他们都说谎了。

#include <algorithm>
#include <iostream>
#include<bits/stdc++.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define INF 0x3f3f3f3f
#define next fuck
#define G 9.8
using namespace std;
const double pi = acos(-1);
const int maxn =1e5 +  5;
int f[maxn];
int Find(int x)
{
    //sz[x]++;
    return f[x] == x ? x : f[x] = Find(f[x]);
}

vector<int> edge[maxn];
int next[maxn],v[maxn],vis[maxn];
int mark[maxn];
void init(int n)
{
    for(int i = 1;i<=n;i++) f[i]= i,vis[i] = 0,mark[i]= 0 ,edge[i].clear();
}
int main()
{
    int T;
    int n;
    char op[20];
    int t;
    scanf("%d",&T);
    queue<int> q;
    while(T--)
    {
        scanf("%d",&n);
        init(n);
        for(int i = 1;i<=n;i++)
        {
            scanf("%d %s",&v[i],op);
            vis[i] = (op[0] == 'v');
            if(vis[i])
            {
                edge[v[i]].push_back(i);
                //vis[v[i]] = 1;
                f[i]= f[Find(v[i])];
            }

        while(!q.empty()) q.pop();
        for(int i = 1;i<=n;i++)
        {
            if(!vis[i])
            {
                int fa = Find(i);
                int fb = Find(v[i]);
                if(fa != fb) continue;
                q.push(v[i]);
                mark[v[i]]=  1;
            }
        }
        int ans =0;
        while(!q.empty())
        {
            int u = q.front();
            q.pop();
            ans++;
            for(int v : edge[u])
            {
                if(!mark[v])
                {
                    q.push(v);
                    mark[v] = 1;
                }
            }
        }
        printf("0 %d\n",ans);
    }

    return 0;
}

1002 bookshelf
这道题就是那道反演,做法具体就是枚举下GCD,然后计数一下,最后注意要对fib-number取模1e9+6
怎么推的式子以后再补上吧

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define next fuck
const int MAXN = 1e6 + 10;
const ll mod = 1e9+7;
ll inv[2*MAXN],fac[2*MAXN];
void init() //o(n)的组合数
{
    inv[0]=fac[0]=1;
    inv[1]=1;
    for(int i=1; i<2*MAXN; i++)
        fac[i]=fac[i-1]*i%mod;
    inv[1]=1;
    for(int i=2; i<2*MAXN; i++)
        inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
    inv[0]=1;
    for(int i=1; i<2*MAXN; i++)
        inv[i]=inv[i-1]*inv[i]%mod;
}
ll com(int n,int m)
{
    //if(n <0 || m <0 || m > n) return 0;
    return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
bool check[MAXN+10];
int prime[MAXN+10];
int mu[MAXN+10];
void Mobius()
{
    memset(check,false,sizeof(check));
    mu[1] = 1;
    int tot = 0;
    for(int i = 2; i <= MAXN; i++)
    {
        if( !check[i] )
        {
            prime[tot++] = i;
            mu[i] = -1;
        }
        for(int j = 0; j < tot; j++)
        {
            if(i * prime[j] > MAXN)
                break;
            check[i * prime[j]] = true;
            if( i % prime[j] == 0)
            {
                mu[i * prime[j]] = 0;
                break;
            }
            else
            {
                mu[i * prime[j]] = -mu[i];
            }
        }
    }
}
ll pow_mod(ll a,ll n)
{
    ll res = 1,b = a % mod;
    while(n)
    {
        if(n & 1) res = res * b % mod;
        b = b * b % mod;
        n >>= 1;
    }
    return res;
}
vector<ll> d;
ll f[MAXN+10],fib[MAXN+10];
int main()
{
    int ca,n,k;
    Mobius();
    init();
    fib[0] = 0,fib[1] = 1;
    for(int i  =2;i<=MAXN;i++)
    {
        fib[i] = (fib[i-1] + fib[i-2])% (mod-1);
    }
    scanf("%d",&ca);
    while(ca--)
    {
        scanf("%d%d",&n,&k);
        d.clear();
        for(int i = 1;i<=n;i++) if(n % i == 0) d.push_back(i);

        memset(f,0,sizeof(f));
        for(int i = 0;i<d.size();i++)
        {
            for(int j = i;j<d.size();j++)
            {
                if(d[j] % d[i] == 0)
                {
                    f[i] = ((f[i] + 1LL*mu[d[j]/d[i]]*com(n/d[j]+k-1,n/d[j]))%mod + mod)%mod;
                }
            }
        }
        ll ans = 0;
        for(int i = 0;i<d.size();i++)
        {
           // cout<<pow_mod(2,fib[d[i]])<<endl;
            ans = (ans + f[i]*(pow_mod(2,fib[d[i]]) -1))% mod ;
            //ans = (ans% mod + mod) % mod;
        }
        ans = ans * pow_mod(com(n+k-1,k-1),mod-2)% mod;
        if(ans <0 ) ans = (ans + mod) % mod;
        printf("%I64d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值