小白月赛题1
小白月赛31
A-A|B:动态规划
题目大意:
给定a和x,找出有多少个b满足 1<= b <= x , a|b = a+b
思路:
我们先把a和x用二进制形式表示,然后从最高位到最低位填满b。
如果要a|b=a+b,那么a和b相同的位不能位1,只能为零。又因为1<=b<=x,如果a的第i位是0,x的第i位是0,并且x的前缀和b的前缀相同,那么b的第i位只能0,否则b>x,但如果x的第i位是1,那么
b的第i位可以取0或1.
所有我们要求从第i位开始x的前缀和和b的前缀相等和不等的填充方法数,用dp[i][0]来表示b的第i位的前缀和x的第i位前缀不相等的方法数,dp[i][1]相等的方法数。
转移方程:看注释
初值:dp[30][1] = 1
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#include <list>
#define ull unsigned long long
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int N = 500005;
const ll ds = 1e15+7;
const double p1 = 3.141592653589793238462643383;
const ull res = 233;
using namespace std;
ll dp[55][2];
int main()
{
int t,a,b,x;
cin >> t;
while(t--){
cin >> a >> x;
ll ans = 1;
memset(dp,0,sizeof(dp));
dp[30][1] = 1;
for(int i = 29; i >= 0; i--){
//a i 1
if(a&(1<<i)){
//b i 0 ,b的第i为必填0
if(x&(1<<i)) dp[i][0] = dp[i+1][0] + dp[i+1][1];//x的第i位与b的第i位不同
else{//相同
//结果和之前的相同
dp[i][1] = dp[i+1][1];
dp[i][0] = dp[i+1][0];
}
}
else{
//b i 0/1
if(x&(1<<i)){
//x i 1
dp[i][0] = dp[i+1][0]*2 + dp[i+1][1];//b的第i位取0,不同了
dp[i][1] = dp[i+1][1];
//或者dp[i][0] = dp[i+1][0]; //取1,相同,那结果和之前的相同
//dp[i][1] = dp[i+1][1];
}
else{
//x i 0
//只有前缀不等才能前1,否则只能填0,同样分两种情况讨论
dp[i][0] = dp[i+1][0]*2;
dp[i][1] = dp[i+1][1];
}
}
}
cout << dp[0][0] + dp[0][1] - 1 << endl;
}
return 0;
} C-图像存储:dfs判连通块+哈希
思路:
从某个点开始深度优先搜索下去得到dfs序,这些点是一块,并标记已经走过,再从下一个点进行判断。
然后用哈希值判断各个联通块是否可以平移重合在一起。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#include <list>
#define ull unsigned long long
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int N = 500005;
const ll ds = 1e15+7;
const double p1 = 3.141592653589793238462643383;
const ll res = 233;
using namespace std;
char s[1005][1005];
int dir[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};
int vis[1005][1005],n,m;
ll k = 0;
map<ll,ll>mp;
bool check(int x,int y)
{
if(x < 0 || x >= n || y < 0 || y >= m) return false;
return true;
}
void dfs(int x,int y)
{
for(int i = 0; i < 4; i++){
int X = x+dir[i][0];
int Y = y+dir[i][1];
if(check(X,Y) && !vis[X][Y] && s[X][Y] == '1'){
vis[X][Y] = 1;
dfs(X,Y);
k = (k*res%mod+5)%mod;
}
k = (k*res%mod+13)%mod;
}
}
int main()
{
while(~scanf("%d%d",&n,&m)){
if(n == 0 && m == 0) break;
mp.clear();
//getchar();
memset(vis,0,sizeof(vis));
for(int i = 0; i < n; i++){
scanf("%s",s[i]);
}
int cnt = 0,ans = 0;
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(s[i][j] == '1' && !vis[i][j]){
cnt++;
vis[i][j] = 1;
k = 0;
dfs(i,j);
if(!mp[k]) ans++,mp[k] = 1;
}
}
}
printf("%d %d\n",cnt,ans);
}
return 0;
}
E-解方程:数论
题目大意:
已知正整数a,b,求正整数x,y,满足a*x+b*y=x*y的组数。
思路:
式子做下变换
a*x+b*y+a*b=x*y+a*b
a*b = x*y-a*x-b*y+a*b
a*b = (x-b)*(y-a)
所以就是求a*b的因子有多少个。
因为 1<=a,b <= 1e6, 则1<=a*b<=1e12
那么不能直接求a*b的因子个数,可以将a*b作质因子分解,我们知道
,N的因子个数就为
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#include <list>
#define ull unsigned long long
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int N = 500005;
const ll ds = 1e15+7;
const double p1 = 3.141592653589793238462643383;
const ull res = 233;
using namespace std;
ll solve(ll cj)
{
ll ans = 1;
int flag = 0;
for(ll i = 2; i*i <= cj; i++){
if(cj%i == 0){
flag = 1;
int cnt = 0;
while(cj%i == 0) {
cj /= i;
cnt++;
}
ans = (cnt+1)*ans;
}
}
if(cj > 1) ans *= 2;
return ans;
}
int main()
{
int a,b,t;
cin >> t;
while(t--){
cin >> a >> b;
ll cj = 1ll*a*b;
if(cj == 1) cout << 1 << endl;
else cout << solve(cj) << endl;
}
return 0;
} F-消去整数:数论
题目大意:
给一个正整数n,让n依次减去1,2,3...直至减位零为止,如果不能减了,则加上n再重复,问需要重复几个这样的过程。
思路:
如果能够一次完成,那么答案为1,
如果不行,那假设减到了x,n剩余y,可知y<x,那再加上n之后,n变成n+y,继续从1开始减,因为y < x,所以最后只能减到x,如果y+y > x,
那么n剩余y+y-x,同理第3次后n剩余y+y+y-x-x,同理重复i次后剩余y*i-k*x,如果y*i-k*x = 0,即是x的最小公倍数是y*i,答案就是i。
i*y = 0 (mod x)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#include <list>
#define ull unsigned long long
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int N = 500005;
const ll ds = 1e15+7;
const double p1 = 3.141592653589793238462643383;
const ull res = 233;
using namespace std;
int solve(int n)
{
int x = 1;
while(n >= x){
n -= x;
x++;
}
for(int i = 1; ;i++){
if(i*n%x == 0) {
return i;
}
}
}
int main()
{
int t,n;
cin >> t;
while(t--){
cin >> n;
cout << solve(n) << endl;
}
return 0;
} 小白月赛17
F-小黄鸭:数学积分+二分答案
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#include <list>
#define ull unsigned long long
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int N = 500005;
const ll ds = 1e15+7;
const double p1 = 3.141592653589793238462643383;
const ll res = 233;
using namespace std;
int main()
{
int R,m;
cin >> R >> m;
double res = 0,l = 0,r = 2*R;
while(r-l > 1e-4){
double mid = (l+r)/2.0;
if(p1*(-1*mid*mid*mid/3.0+mid*mid*R) > m)
r = mid;
else
l = mid;
}
// printf("%.2f\n",res);
double ans = 2*R-r;
printf("%.2f",ans);
return 0;
} G-区间求和:莫队(模板题)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#include <list>
#define ull unsigned long long
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int N = 500005;
const ll ds = 1e15+7;
const double p1 = 3.141592653589793238462643383;
const ll res = 233;
using namespace std;
int n,m,block,l = 1,r = 0;
ll now = 0;
struct Node{
int l,r,xb;
// bool operator < (const Node &a) const{
// if(a.l/block == l/block) return a.r > r;
// else return a.l/block > l/block;
// }
}node[100005];
ll a[100005],cnt[100005];
ll ans[100005];
void add(int t)
{
now -= cnt[a[t]]*a[t]*cnt[a[t]];
cnt[a[t]]++;
now += cnt[a[t]]*a[t]*cnt[a[t]];
}
void del(int t)
{
now -= cnt[a[t]]*a[t]*cnt[a[t]];
// if(cnt[a[t]] > 0){//这步不能加
cnt[a[t]]--;
now += cnt[a[t]]*a[t]*cnt[a[t]];
// }
}
bool cmp(Node q1,Node q2)
{
if(q1.l/block == q2.l/block) return q1.r < q2.r;
return q1.l/block < q2.l/block;
}
int main()
{
scanf("%d%d",&n,&m);
block = sqrt(n);
for(int i = 1; i <= n; i++) scanf("%lld",&a[i]);
for(int i = 1; i <= m; i++){
scanf("%d%d",&node[i].l,&node[i].r);
node[i].xb = i;
}
sort(node+1,node+m+1,cmp);
for(int i = 1; i <= m; i++){
while(l < node[i].l) del(l++);
while(l > node[i].l) add(--l);
while(r < node[i].r) add(++r);
while(r > node[i].r) del(r--);
ans[node[i].xb] = now;
}
for(int i = 1; i <= m; i++){
printf("%lld\n",ans[i]);
}
return 0;
} H-取数游戏:期望dp
思路:
求期望,概率等一般考虑用dp。
找状态:dp[i][j]:表示拿i次后桌子上有j个球的概率。
状态转移:dp[i][j] = dp[i-1][j-1]*(c-j+1)/c+dp[i-1][j+1]*(j-1)/c 第i次从剩余(c-j+1)种球拿一个桌子上成为j个,从j+1种球拿一个和桌子上的某个球相同,拿走一个,桌子上剩余j个。
初值:dp[0][0] = 1.00
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#include <list>
#define ull unsigned long long
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int N = 500005;
const ll ds = 1e15+7;
const double p1 = 3.141592653589793238462643383;
const ll res = 233;
using namespace std;
double dp[10050][105];
int main()
{
int c,m;
ll n;
scanf("%d%lld%d",&c,&n,&m);
if((n&1) != (m&1)){
printf("0.000\n");
return 0;
}
if(n >= 1e4) n = 1e4+(n%2);
dp[0][0] = 1.00;
for(int i = 1; i <= n; i++){
for(int j = 0; j <= c; j++){
if(j) dp[i][j] = dp[i-1][j-1]*1.0*((c-j+1)*1.0/c*1.0) + 1.0*dp[i-1][j+1]*((j+1)*1.0/c*1.0);
else dp[i][j] = dp[i-1][j+1]*1.0*((j+1)*1.0/c*1.0);
}
}
printf("%.3lf",dp[n][m]);
return 0;
} 小白月赛16
D-小阳买水果:前缀和
大意:
给定n个水果的满意度,只能买一段连续的水果,在保证满意度大于零的情况下长度最大是多少。
思路;
重载结构体,按前缀和从小到大排序,这样相减后中间那段一定大于零,前缀和相同按下标从大到小排序,可以保证排除某段连续为零的情况。为了求到最大值,维护一个最小的下标min_xb。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#include <list>
#define ull unsigned long long
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 911451407;
const int N = 500005;
const ll ds = 1e15+7;
const double p1 = 3.141592653589793238462643383;
const ll res = 233;
using namespace std;
struct Node{
int xb;
ll x;
bool operator < (const Node &a) const{
if(a.x == x) return a.xb < xb;
else return a.x > x;
}
}node[2000005];
int main()
{
int x,n;
scanf("%d",&n);
for(int i = 1; i <= n; i++){
scanf("%d",&x);
node[i].xb = i;
node[i].x = node[i-1].x+x;
}
sort(node,node+n+1);
int ans = 0,min_xb = node[0].xb;
for(int i = 0; i <= n; i++){
ans = max(ans,node[i].xb-min_xb);
min_xb = min(min_xb,node[i].xb);
}
printf("%d",ans);
return 0;
} 小白月赛 文章被收录于专栏
希望通过写小白月赛来提升自己的算法能力。