Educational Codeforces Round 80 (Rated for Div. 2)
https://codeforces.com/contest/1288
A. Deadline
思路1:先不看取顶符号,求一次导发现大概在 d \sqrt{d} d左右达到最小值,再在两边找最小值即可
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t,n,d;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&d);
int sq = sqrt(d);
int minn = 1e9+5;
for(int i = max(0,sq-10000);i <= sq + 10000;++i)
minn = min(minn,i+(int)ceil(1.0*d/(i+1)));
if(minn <= n)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
思路2:数论分块
见:https://blog.csdn.net/xing_mo/article/details/104000119
B. Yet Another Meme Problem
思路:ab+a+b=conc(a,b) => ab+a = a*bit(b)(这里bit(b)表示b的位数)=> b = bit(b)-1
即求出b的个数然后乘上A即可,b形如9,99,999,…
#include<bits/stdc++.h>
using namespace std;
int t,a,b;
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&a,&b);
int tmp = b,cnt = 0;
while(tmp)
{
tmp/=10;
++cnt;
}
--cnt;
if(b == (1ll*pow(10ll,1ll*cnt+1)-1))
++cnt;
printf("%lld\n",1ll*cnt*a);
}
return 0;
}
C. Two Arrays
思路1:
d
p
[
i
]
[
j
]
[
k
]
dp[i][j][k]
dp[i][j][k]表示第i位b数组为j,a数组为k时的方案数,可由
d
p
[
i
−
1
]
[
n
.
.
.
j
]
[
1...
k
]
dp[i-1][n...j][1...k]
dp[i−1][n...j][1...k]求和得出,而求和时控制遍历顺序可以利用上一层的结果,无需全部求一次
思路2:见https://blog.csdn.net/xing_mo/article/details/103999999
#include<bits/stdc++.h>
#define MAXN 1005
#define ll long long
using namespace std;
const int MOD = 1e9+7;
int n,m,dp[15][MAXN][MAXN],sum[MAXN];
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i = 1;i <= n;++i)
for(int j = 1;j <= n;++j)
if(i >= j)
dp[1][i][j] = 1;
else
dp[1][i][j] = 0;
for(int i = 2;i <= m;++i)
{
memset(sum,0,sizeof(int)*(n+1));
for(int j = n;j >= 1;--j)
{
int tmp = 0;
for(int k = 1;k <= j;++k)
{
tmp = (tmp+dp[i-1][j][k])%MOD;
dp[i][j][k] = (tmp+sum[k])%MOD;
sum[k] = dp[i][j][k];
}
for(int k = j+1;k <= m;++k)
dp[i][j][k] = 0;
}
}
int ans = 0;
for(int i = 1;i <= n;++i)
for(int j = 1;j <= n;++j)
ans = (ans + dp[m][i][j])%MOD;
printf("%d\n",ans);
}
return 0;
}
D. Minimax Problem
思路:注意m只有8,二分答案,设为mid,将所有ai数组中大于mid的位置置为1,小于mid的位置置为0,然后将ai状压,用一个vis记录每种状态是否出现过,最后两个for循环遍历vis数组,如果存在i状态和j状态都出现并且他们的或是满状态,则表示存在两个数组可以得到大于等于mid的结果,增大l
最后对于一个最大值ans,类似上面操作将那两个状态对应数组的标号找出来即可
#include<bits/stdc++.h>
#define MAXN 300005
using namespace std;
int mp[MAXN][10],vis[1<<9];
int n,m;
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i = 1;i <= n;++i)
for(int j = 0;j < m;++j)
scanf("%d",&mp[i][j]);
int l = 0,r = 1e9,mid,ans;
int uu = (1<<m)-1;
while(l <= r)
{
mid = (l+r) >> 1;
memset(vis,0,sizeof(vis));
for(int i = 1;i <= n;++i)
{
int tmp = 0;
for(int j = 0;j < m;++j)
if(mp[i][j] >= mid)
tmp += (1<<j);
vis[tmp] = 1;
}
bool flag = false;
for(int i = 0;i < (1<<m);++i)
for(int j = 0;j < (1<<m);++j)
if(vis[i] && vis[j] && (i|j) == uu)
flag = true;
if(flag)
{
ans = mid;
l = mid+1;
}
else
r = mid-1;
}
memset(vis,0,sizeof(vis));
for(int i = 1;i <= n;++i)
{
int tmp = 0;
for(int j = 0;j < m;++j)
if(mp[i][j] >= ans)
tmp += (1<<j);
vis[tmp] = i;
}
int a,b;
for(int i = 0;i < (1<<m);++i)
for(int j = 0;j < (1<<m);++j)
if(vis[i] && vis[j] && (i|j) == uu)
{
a = vis[i],b = vis[j];
break;
}
printf("%d %d\n",a,b);
}
return 0;
}