codeforces1700数学:E2. Close Tuples (hard version)[组合计数 逆向统计] D. Circle Game[对称博弈考虑对称状态的胜负]

E2. Close Tuples (hard version)


题目大意:
给 定 一 个 长 度 为 n 的 序 列 a , 给定一个长度为n的序列a, na
要 从 中 挑 选 一 个 m 元 组 ( a i 1 , a i 2 , a i 3 . . . a i m ) [ i 1 < i 2 < i 3 . . . . < i m ] 要从中挑选一个m元组(ai_1,ai_2,ai_3...ai_m)[i_1 < i_2 < i_3....<i_m] m(ai1,ai2,ai3...aim)[i1<i2<i3....<im]满足:
在这里插入图片描述
问 有 多 少 种 这 样 的 组 合 ? 问有多少种这样的组合?


解题思路:
首 先 我 们 不 能 被 后 面 下 标 的 限 制 所 迷 惑 它 只 是 想 表 达 数 字 不 能 被 重 复 选 择 而 已 , 首先我们不能被后面下标的限制所迷惑它只是想表达数字不能被重复选择而已,
那 么 我 们 可 以 把 a 数 组 进 行 排 序 , 这 样 就 好 选 一 点 , 在 排 序 好 的 数 组 中 , 我 们 那么我们可以把a数组进行排序,这样就好选一点,在排序好的数组中,我们 a
把 对 每 个 a i 算 一 下 贡 献 , 但 是 我 们 为 了 不 让 序 列 重 复 统 计 我 们 可 以 这 样 把对每个ai算一下贡献,但是我们为了不让序列重复统计我们可以这样 ai,

假 设 a i 是 长 度 为 m 的 序 列 中 的 最 大 值 , 那 么 我 们 就 可 以 从 假设a_i是长度为m的序列中的最大值,那么我们就可以从 aim
[ 1 , i − 1 ] 位 置 里 面 找 到 第 一 个 a j 使 得 a j ≤ a i & & a i − a j ≤ k 所 以 我 们 就 可 以 保 证 序 列 可 以 不 被 重 复 计 算 , 假 设 那 个 位 置 是 p o s , 那 么 我 们 要 保 证 最 大 值 一 定 要 被 选 的 情 况 下 在 [ p o s , i − 1 ] 里 面 挑 m − 1 个 数 就 可 以 了 [1,i-1]位置里面找到第一个a_j使得a_j\leq a_i\&\&ai-aj \leq k所以我们就可以保证序列可以不被重复计算,假设那个位置是pos,那么我们要保证最大值一定要被选的情况下在[pos,i-1]里面挑m-1个数就可以了 [1,i1]aj使ajai&&aiajk,pos,[pos,i1]m1
a n s = ∑ i = 1 n C i − p o s m − 1 ans=\sum_{i=1}^{n} C_{i-pos}^{m-1} ans=i=1nCiposm1


#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>

using namespace std;

const int mod = 1e9+7;
const int N = 200010;

#define ll long long

int n, T;
int a[N];
int m, k;

ll quick_pow(int a,int b)
{
    ll res = 1;
    while(b)
    {
        if(b&1) res=res*a%mod;
        a=(ll)a*a%mod;
        b>>=1;
    }
    return res;
}

ll C(int n, int m)
{
    if(n<m) return 0;
    ll up = 1, down = 1;
    for(int i=n;i>n-m;i--) up=up*i%mod;
    for(int i=1;i<=m;i++) down=down*i%mod;
    down = quick_pow(down,mod-2);
    return up*down%mod;
}

int main()
{
    ios::sync_with_stdio(false);
    
    cin>>T;
    while(T--)
    {
        cin>>n>>m>>k;
        for(int i=1;i<=n;i++) cin>>a[i];
        sort(a+1,a+n+1);
        ll ans = 0;
        for(int i=1;i<=n;i++)
        {
            int pos = lower_bound(a+1,a+i+1,a[i]-k) - a;
            ans = (ans + C(i - pos, m - 1))%mod;
        }
        cout<<ans<<endl;
    }
    return 0;
}

D. Circle Game


题目大意:
就 是 给 你 一 个 圆 形 状 的 区 域 , 两 个 人 从 ( 0 , 0 ) 点 开 始 每 次 移 动 一 个 棋 子 向 上 或 者 向 右 移 动 k 步 , 最 后 谁 把 就是给你一个圆形状的区域,两个人从(0,0)点开始每次移动一个棋子向上或者向右移动k步,最后谁把 (0,0)k 棋 子 移 动 出 了 圆 形 区 域 就 输 了 , 问 你 最 后 是 谁 赢 了 棋子移动出了圆形区域就输了,问你最后是谁赢了


解题思路:
1. 通 过 观 察 可 以 知 道 这 是 一 个 对 称 博 弈 那 么 我 们 只 要 考 虑 中 间 对 角 线 的 位 置 的 胜 负 状 态 因 为 x 和 y 都 是 增 加 , 如 果 对 角 线 是 必 败 态 那 么 先 手 必 定 会 远 离 , 但 是 后 手 会 尽 可 能 的 去 靠 近 对 角 线 , 1.通过观察可以知道这是一个对称博弈那么我们只要考虑中间对角线的位置的胜负状态因为x和y都是增加,如果对角线是必败态那么先手必定会远离,但是后手会尽可能的去靠近对角线, 1.线xy线线
2. 同 理 可 得 2.同理可得 2.
那 么 我 们 只 要 判 断 对 角 线 上 的 最 后 的 点 的 状 态 : 那么我们只要判断对角线上的最后的点的状态: 线


#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
int T;
ll d, k;
int main() {
	cin >> T;
	while(T--) {
		cin >> d >> k;
		ll x = 0;
		while(2ll * (x + k) * (x + k) <= d * d) x += k;//判断最靠近边界的状态
		if((x + k) * (x + k) + x * x <= d * d) {
			printf("Ashish\n");
		} else {
			 printf("Utkarsh\n");
		}
	}
	return 0;
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值