1. 程式人生 > 其它 >codeforces1700數學:E2. Close Tuples (hard version)[組合計數 逆向統計] D. Circle Game[對稱博弈考慮對稱狀態的勝負]

codeforces1700數學:E2. Close Tuples (hard version)[組合計數 逆向統計] D. Circle Game[對稱博弈考慮對稱狀態的勝負]

技術標籤:codeforce1700數學

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(ai

1,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 & & [1,i-1]位置裡面找到第一個a_j使得a_j<=a_i\&\&

[1,i1]aj使aj<=ai&&
a i − a j < = k 所 以 我 們 就 可 以 保 證 序 列 可 以 不 被 重 復 計 算 , 假 設 那 個 位 置 是 p o s ai-aj<=k所以我們就可以保證序列可以不被重複計算,假設那個位置是pos aiaj<=k,pos
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


題目大意:略


解題思路:通過觀察可以知道這是一個對稱博弈那麼我們只要考慮中間對角線的位置的勝負狀態
因為x和y都是增加,如果對角線是必敗態那麼先手必定會遠離,但是後手會盡可能的去靠近對角線,同理可得
那麼我們只要判斷對角線上的最後的點的狀態:


#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;
}