#include
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define db double
#define Pir pair
#define PIR pair
#define INF 0x3f3f3f3f
#define mod 998244353
const int mxn = 2e5 + 10;
int n, d;
int main()
{
/* fre(); */
int T;
scanf("%d", &T);
while(T --)
{
scanf("%d %d", &n, &d);
if(ceil(2 * sqrt(d) - 1) <= n)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
#include
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define db double
#define Pir pair
#define PIR pair
#define INF 0x3f3f3f3f
#define mod 998244353
const int mxn = 2e5 + 10;
int n, d;
int main()
{
/* fre(); */
int T;
scanf("%d", &T);
while(T --)
{
ll a; string s;
cin >> a >> s;
ll b = s.size();
int fg = 0;
for(auto x : s)
{
if(x != '9')
{
fg = 1;
break;
}
}
b -= fg;
printf("%lld\n", a * b);
}
return 0;
}
第一部分:规定dp[i][j]所代表的序列的最后一位(即:第i为)为j,那么剩下从第1位~到第i-1位的方案数是dp[i-1][j]
第二部分:规定dp[i][j]所代表的序列的最后一位不是j,那么总的1~i位的方案数位dp[i][j-1]
这两部分组成了dp[i][j]的方案数的全集
#include
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define db double
#define Pir pair
#define PIR pair
#define INF 0x3f3f3f3f
#define mod (ll)(1e9 + 7)
const int mxn = 3e5 + 10;
int dp[25][1005];
int main()
{
/* fre(); */
int n, m;
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i ++)
dp[1][i] = 1;
m *= 2;
for(int i = 2; i <= m; i ++)
for(int j = 1; j <= n; j ++)
dp[i][j] = (dp[i][j - 1] + dp[i - 1][j]) % mod;
int res = 0;
for(int i = 1; i <= n; i ++)
res = (res + dp[m][i]) % mod;
printf("%d", res);
return 0;
}
#include
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define db double
#define Pir pair
#define PIR pair
#define INF 0x3f3f3f3f
#define mod (ll)(1e9 + 7)
const int mxn = 3e5 + 10;
ll q_pow(ll a, ll b)
{
ll res = 1;
while(b)
{
if(b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
ll cal(ll a, ll b)
{
ll f[mxn];
f[0] = 1;
for(int i = 1; i <= 1025; i ++)
f[i] = f[i - 1] * i % mod;
ll up = f[a];
ll down = f[b] * f[a - b] % mod;
return up * q_pow(down, mod - 2) % mod;
}
int main()
{
/* fre(); */
int n, m;
scanf("%d %d", &n, &m);
printf("%lld", cal(2 * m + n - 1, n - 1));
return 0;
}
最小的元素尽可能的大
,输入i,j (注意:i可以与j相同)这一题的思路不得不让人觉得奇妙!!!
看到:最小的元素尽可能的大
,其实我们可以考虑一下二分,这题的如果用二分,我们肯定是在[1,1e9]的范围内枚举c中最小元素的值
设为md,能否通过在n中合理的选择两个序列来实现这个最小的枚举值md?我们肯定不可以用两层for循环暴力枚举合适的序列 a i , a j a_i,a_j ai,aj,之后在用一层for循环枚举判读每个 a i , a j a_i,a_j ai,aj位置,这里有两个难点:1不能不能暴力枚举ai、aj序列、2不能对枚举出来的两个序列进行一位一位的枚举判读,这样两个难点是我们要优化的地方
于是我们就见到了神奇的 二进制枚举
, 那么怎么枚举呢?
两个序列:a1 = { 1, 2, 3 ,4}、a2{2、1、3、2},我们假设m = 4,枚举最小值md=2,我们下面要这两个序列要做操作是如果 序列中的某个元素>=md,它所对应的二进制位1,否则0,,,那么转化完之后对应的为两个二进制数字:a1->b1=0111,a2->b2=1011,
通过这样的转化我们可以将n个a数组,转化位n个二进制数,而这样的二进制数最多有 t=1<
)接下来我们看看第二个难题是怎么解决的:我们判断: b 1 ∣ b 2 = = ( 1 < < = m ) − 1 b1 | b2==(1<<=m)-1 b1∣b2==(1<<=m)−1这个等式是否成立,如果成立就意味着: b 1 ∣ b 2 = 1111 b1|b2=1111 b1∣b2=1111,否则会出现例如 1101 、 0101 、 1110 1101、0101、1110 1101、0101、1110等等情况,都表明b1、b2的对应的二进制位上出现同时存在0的情况,那么翻译到 a 1 、 a 2 a1、a2 a1、a2两个序列中的意思是,就是这两个序列中的某些个位置上的元素同时出现了 通过这个 | 操作元素符以O(1)的时间完成了对两个二进制数的判读,间接的完成了对序列a1、a2的元素的判断,这就解决了第2个难题了
通过这个例子我们大致明白了,二进制枚举的过程,其它的就是代码问题,剩下直接看代码
1.对于我们时候二分法枚举答案的时候,对与 数据量大、所有状态难以一一暴力比较的时候,我可以考虑用 二进制枚举,来优化 暴力枚举时的状态过多的问题
#include
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define db double
#define Pir pair
#define PIR pair
#define INF 0x3f3f3f3f
#define mod (ll)(1e9 + 7)
const int mxn = 3e5 + 10;
int ar[mxn][10];
int n, m;
int a1, a2;
void rd(int & x)
{
int ans = 0, f = 1; char ch = getchar();
while(! isdigit(ch)) { if(ch == '-') f = -1; ch = getchar(); }
while( isdigit(ch)) { ans *= 10; ans += ch - '0'; ch = getchar(); }
x = ans;
}
bool judge(int md)
{
vector<int> bit(1 << m, -1); //n个数列最多产生,1 << m 种情况(每种情况 经过二进制转化之后 对应一个 bit容器下标),初始化为-1:表示 数对应的情况不存在
//遍历统计 哪些情况出现过
for(int i = 0; i < n; i ++)
{
int idx = 0;
for(int j = 0; j < m; j ++)
if(ar[i][j] >= md)
idx ^= (1 << j);
bit[idx] = i; //bit容器存储对应情况的 数组下标
}
//特殊情况(作为答案的两个数组 是同一个数组)
for(int i = 0; i < (1 << m); i ++)
if(bit[(1 << m) - 1] != -1)
{
a1 = a2 = bit[(1 << m) - 1];
return true;
}
//暴力枚举255 x 255 种情况
for(int i = 0; i < (1 << m); i ++)
for(int j = 0; j < (1 << m); j ++)
{
if(bit[i] != -1 && bit[j] != -1 && (i | j) == (1 << m) - 1)
{
a1 = bit[i], a2 = bit[j]; return true;
}
}
return false;
}
int main()
{
/* fre(); */
/* rd(n), rd(m); */
scanf("%d %d", &n, &m);
for(int i = 0; i < n; i ++)
for(int j = 0; j < m; j ++)
/* rd(ar[i][j]); */
scanf("%d", &ar[i][j]);
int l = 0, r = 1e9;
while(l <= r)
{
int md = l + r >> 1;
if(judge(md))
l = md + 1;
else
r = md - 1;
}
printf("%d %d", a1 + 1, a2 + 1);
return 0;
}
把某个元素a中的某个元素bi移动到首位置之后,我们要把所以有在bi之前的元素都向后平移1位,由于a中的元素非常多,我们不可能一位一位的向后平移
,举例
a数组:1 2 3 4
b数组:3 2
我们预留空位之后a数组变为:0 0 1 2 3 4,
在第一次操作之前:我们 用树状数组统计维护将要被操做元素3之前的元素个数ct,并且维护3的最大位置 r[3]=max(3, ct+1)
第一次操作:我们把3平移到首位:0 3 1 2 0 4,
在第二次操作之前:我们 用树状数组统计维护将要被操做元素2之前的元素个数ct,并且维护2的最大位置 r[2]=max(2, ct+1)
第二次操作:我们包2平移的首位:2 3 1 0 0 4,
最后我们 在对所有元素跑一遍 树状数组,统计每个元素的前面有几个元素,并且维护:对应每个元素 位置最大值
对于a中某个元素,位置最小值,只要这个元素在b中出现过,那么就是1,
#include
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define db double
#define Pir pair
#define PIR pair
#define INF 0x3f3f3f3f
#define mod (ll)(1e9 + 7)
const int mxn = 6e5 + 10; //因为要预留空间,所以数组c要开2倍大
int c[mxn];
int l[mxn], r[mxn];
int pos[mxn];
int n, m;
int lowbit(int x) { return x & (-x); }
void add(int p, int t)
{
while(p < mxn) { c[p] += t; p += lowbit(p); }
}
int ask(int p)
{
int sum = 0;
while(p) { sum += c[p]; p -= lowbit(p); }
return sum;
}
int main()
{
/* fre(); */
int n, m;
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i ++)
{
l[i] = r[i] = i;
add(i + m, 1);
pos[i] = i + m;
}
int last = m;
while(m --)
{
int x;
scanf("%d", &x);
l[x] = 1;
int num = ask(pos[x]);
r[x] = max(r[x], num); //维护最大值
if(num == 1) continue; //如果时在第1位直接跳过
add(pos[x], -1); //移出
pos[x] = last; //添加到第1位,所在的位置
add(pos[x], 1); //添加到第1位
last --; //第一位 所在的位置往前挪1
}
//重新维护一下所有数的位置
for(int i = 1; i <= n; i ++)
r[i] = max(r[i], ask(pos[i]));
for(int i = 1; i <= n; i ++)
printf("%d %d\n", l[i], r[i]);
return 0;
}