全程NOIP计划 模拟赛1

说在前面

这场比赛打炸了,听说是套路题,但是除了会骗点t1的分啥都不会。
预期:100+75+10+10
实际:90+36+0+10
(捆绑测试fn)
yzhang和dead_X差点ak,orz。

A 平面几何

考察:写代码能力,小思维(?)

我考场上尝试(mathcal{O}(n^2))(没跑满)+极限卡常,可惜还是失败了。
考虑作一条(Y = a)的直线,其中(a)是一个很大的值。
发现他们与直线的交点,从(x)轴的左端开始数,一定是斜率大的在左,斜率小的在右。考虑到在这种情况下只有相邻的两条直线才有可能搞出纵坐标最大的交点,所以按照斜率排序然后枚举相邻交点即可。(mathcal{O}(n log {n}))

# include <bits/stdc++.h>
using namespace std;
# define int long long
const int N = 5e4 + 5;
int n;
int ax[N],ay[N],bx[N],by[N],Qu[N];
struct Fenshu
{
    int p,q; // p / q
    Fenshu() {}
    Fenshu(int _p,int _q) : p(_p),q(_q) {}
};

pair<Fenshu,Fenshu> Intersect(int i, int j) {
	long long px = (long long)(ay[j] * bx[j] - ax[j] * by[j]) * (ax[i] - bx[i]) - (long long)(ay[i] * bx[i] - ax[i] * by[i]) * (ax[j] - bx[j]);
	long long py = (long long)(ax[i] * by[i] - ay[i] * bx[i]) * (ay[j] - by[j]) - (long long)(ax[j] * by[j] - ay[j] * bx[j]) * (ay[i] - by[i]);
	int q = (ax[i] - bx[i]) * (ay[j] - by[j]) - (ax[j] - bx[j]) * (ay[i] - by[i]);
	if (q < 0) px *= -1, py *= -1, q *= -1;
    return make_pair(Fenshu(px,q),Fenshu(py,q));
}

bool operator > (const struct Fenshu &x,const struct Fenshu &y)
{
    if(1ll * x.p * 1ll * y.q > 1ll * x.q * 1ll * y.p) return 1;
    else return 0;
}
bool operator < (const struct Fenshu &x,const struct Fenshu &y)
{
    if(1ll * x.p * 1ll * y.q < 1ll * x.q * 1ll * y.p) return 1;
    else return 0;
}
bool compare(int i,int j)
{
    return Fenshu(bx[i] - ax[i],by[i] - ay[i]) < Fenshu(bx[j] - ax[j],by[j] - ay[j]);
}
signed main(void)
{
    scanf("%lld",&n);
    for(int i = 1; i <= n; i++)
    {
        scanf("%lld%lld%lld%lld",&ax[i],&ay[i],&bx[i],&by[i]);Qu[i] = i;
        if(by[i] < ay[i]) swap(by[i],ay[i]),swap(bx[i],ax[i]);
    }
    sort(Qu + 1,Qu + n + 1,compare);
    struct Fenshu ans = Fenshu(-1e9-7,1);
    for(int i = 1; i < n; i++)
    {
        if(Intersect(Qu[i],Qu[i + 1]).second > ans) ans = Intersect(Qu[i],Qu[i + 1]).second;
    }
    // printf("%lld %lld
",ans.p,ans.q);
    printf("%lf
",double(ans.p) / double(ans.q));
    return 0;
}

B. 有向图

考察:构造,图论
首先(m)是奇数显然是(-1),因为(m)即为出度总和,而要求出度为偶数,矛盾。
(m)为偶数一定有解。考虑求出它的一个dfs树,然后将不在dfs树上的随意乱定边,自底向上,根据子树情况判断是否向父亲节点连边。
正确性:不难发现除根节点外其他点都可以通过与父亲节点的连边调整奇偶。那么现在除根外所有点的出度都为偶数,(m)也为偶数,而出度和(= m),那么根节点的出度=(m)-除根外出度和,显然为偶数。

# include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n,m;
vector <int> g[N];
bool vis[N];
int dep[N],cnt[N];
void dfs(int x,int fa)
{
    dep[x] = dep[fa] + 1;
    vis[x] = 1;
    for(int i = 0; i < (int)g[x].size(); i++)
    {
        int v = g[x][i];
        if(v == fa) continue;
        if(vis[v])
        {
            if(dep[v] < dep[x]) 
            {
                cnt[x] ^= 1;
                printf("%d %d
",x,v);
            }
        }
        else dfs(v,x);
    }
    if(!fa) return;
    if(cnt[x]) printf("%d %d
",x,fa);
    else cnt[fa] ^= 1,printf("%d %d
",fa,x);
    return;
}
int main(void)
{
    scanf("%d%d",&n,&m);
    if(m & 1) printf("-1
");
    else
    {
        for(int i = 1; i <= m; i++)
        {
            int u,v; scanf("%d%d",&u,&v);
            g[u].push_back(v),g[v].push_back(u);
        }
        dfs(1,0);
    }
    return 0;
}

(考场上写了除无特殊情况外的75pts,结果被捆绑测试搞挂了一堆)

C 数学题

考察:dp,期望

(dp[i][j])为考虑了前(i)个数,且共选了(j)个数的总和。

[dp[i][j] = left( sum_{c = 0}^j dp[i - 1][j - c] ight) cdot a_i^c ]

搞一下会发现(dp[i][j] = dp[i][j - 1] cdot a_i + dp[i - 1][j])
然后分母是(inom{n + k - 1}{n - 1}),但是我组合数不知道为啥写出来全RE,所以改DP了。

# include <bits/stdc++.h>
using namespace std;
# define int long long
const int N = 1e5 + 5,K = 305;
const int mod = 998244353;
typedef long long ll;
int dp[K],f[K],n,k;
ll qmulti(int x,int p)
{
    int ans = 1;
    while(p)
    {
        if(p & 1) ans = ans = (ll)x * ans % mod;
        x = (ll) x * x % mod;
        p >>= 1;
    }
    return ans % mod;
}
signed main(void)
{
    scanf("%lld%lld",&n,&k);
    dp[0] = f[0] = 1;
    for(int i = 1; i <= n; i++)
    {
        int x; scanf("%lld",&x);
        for(int j = 1; j <= k; j++)
        {
            dp[j] = (dp[j] + dp[j - 1] * x * 1ll) % mod;
            f[j] = (f[j] + f[j - 1] * 1ll) % mod;
        }
    }
    printf("%lld
",(ll)dp[k] * qmulti(f[k],mod - 2) % mod);
    return 0;
}

D 俄罗斯方块

考察:推柿子能力,矩阵快速幂加速递推式
样例再多给一项就可以oeis了,兔可以的嗷

# include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
long long n;
struct Matrix
{
    int a[5][5];
}M;
Matrix operator * (const struct Matrix &x,const struct Matrix &y)
{
    Matrix ans;
    for(int i = 1; i <= 4; i++) for(int j = 1; j <= 4; j++) ans.a[i][j] = 0;
    for(int i = 1; i <= 4; i++) 
    {
        for(int j = 1; j <= 4; j++)
        {
            for(int k = 1; k <= 4; k++) 
                ans.a[i][j] = (ans.a[i][j] + (long long)x.a[i][k] * (long long)y.a[k][j]) % mod;
        }
    } 
    return ans;  
}
Matrix qPOW(Matrix x,long long p)
{
    Matrix ans;
    for(int i = 1; i <= 4; i++) for(int j = 1; j <= 4; j++) ans.a[i][j] = (i == j) ? 1 : 0;
    while(p)
    {
        if(p & 1) ans = ans * x;
        x = x * x,p >>= 1;
    }
    return ans;
}
int main(void)
{
    int T; scanf("%d",&T);
    M.a[1][1] = 1,M.a[1][2] = 2,M.a[1][3] = 0,M.a[1][4] = 2;
    M.a[2][1] = 1,M.a[2][2] = 3,M.a[2][3] = 2,M.a[2][4] = 2;
    M.a[3][1] = 3,M.a[3][2] = 8,M.a[3][3] = 5,M.a[3][4] = 6;
    M.a[4][1] = 1,M.a[4][2] = 2,M.a[4][3] = 1,M.a[4][4] = 2;
    while(T--)
    {
        scanf("%lld",&n);
        struct Matrix ANS = qPOW(M,n / 5);
        printf("%d
",(ANS.a[1][1] + ANS.a[1][2] + 3ll * ANS.a[1][3] + ANS.a[1][4]) % mod);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/luyiming123blog/p/15060647.html