https://ac.nowcoder.com/acm/contest/4784
状压枚举行,复杂度 过了,过的有点莫名其妙。还跑得贼快 15ms
#include
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
char s[20][100005];
int lie[100005];
int temp[100005];
int main()
{
int T;
sc("%d", &T);
while (T--)
{
int n, m, a, b;
sc("%d%d%d%d", &n, &m, &a, &b);
for (int i = 1; i <= m; i++)
lie[i] = 0;
for (int i = 1; i <= n; i++)
{
sc("%s", s[i] + 1);
for (int j = 1; j <= m; j++)
if (s[i][j] == '*')
lie[j]++;
}
for (int i = 0; i < (1 << n); i++)
{
for (int j = 1; j <= m; j++)
temp[j] = lie[j];
int num = 0, cnt = 0;
for (int j = 1; j <= n; j++)
{
if (i & (1 << (j - 1)))
num++;
}
if (num != a)
continue;
for (int j = 1; j <= n; j++)
{
if (i & (1 << (j - 1)))
{
for (int k = 1; k <= m; k++)
if (s[j][k] == '*')
temp[k]--;
}
}
for (int j = 1; j <= m; j++)
{
if (temp[j])
cnt++;
}
if (cnt <= b)
{
pr("yes\n");
goto qwe;
}
}
pr("no\n");
qwe:;
}
}
枚举质因子 p,求出那个质因子个数之后。通过二分来check 个数是否足够。
考虑check的时候,(实际上就是某场div2的C),二分质因子 p 的倍数,假设我们现在选择 p*mid,我们不考虑每个数字含有的 p 的个数,我们考虑选择含有 因子的个数,显然这样很好求,就是
,由于因子最多只有30+个,所以在check 的同时加一个特判就可以了。
#include
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
bool check(ll k, ll num, ll all)
{
ll ans = 0;
for (int i = num; i <= k * num; i = i * num)
{
ans += k * num / i;
if (ans > 50)
return true;
}
if (ans >= all)
return true;
return false;
}
ll get(ll n)
{
ll ans = 1;
for (ll i = 2; i * i <= n; i++)
{
if (n % i == 0)
{
ll cnt = 0;
while (n % i == 0)
{
n /= i;
cnt++;
}
ll l = 1, r = 1e9;
while (l + 1 < r)
{
ll k = (l + r) / 2;
if (check(k, i, cnt))
r = k;
else
l = k;
}
if (!check(l, i, cnt))
l = r;
ans = max(ans, i * l);
}
}
if (n > 1)
{
ans = max(ans, n);
}
return ans;
}
int main()
{
int T;
sc("%d", &T);
while (T--)
{
ll n;
sc("%lld", &n);
pr("%lld\n", get(n));
}
}
完全图就是任意两个点都有边,所以 n-1 条边 多一个连通分量,然后 n-2 条边 多一个连通分量……
但是不太明白为啥出题人出这么大的范围,然后花了很长时间(打开了IDEA)上了一发 BigInteger
import java.math.BigInteger;
import java.util.Scanner;
public class Main{
public static void main(String[] args){
BigInteger one = new BigInteger("1");
Scanner in = new Scanner(System.in);
int T;
T=in.nextInt();
for (int ll=0;ll
感觉这种题没啥意义,PHP一时爽
4294967296
类似今年Camp day1 A(https://ac.nowcoder.com/acm/contest/3979/A),两个题相同在都是从n个范围内选出n个数字,然后算相邻对答案差生的贡献,都用到了期望的可加性
Camp的题是求逆序对的期望,所以只需要考虑相邻的逆序即可
小白赛F是求这个序列最少分成多少个连续不下降子段,所以在考虑相邻变成下降的同时,要乘上除了相邻两个线段的剩下线段的长度积,并且由于无论如何都有一个贡献,在最后加上所有数字任选的情况
然后考虑相邻两段,最多有6种情况,实际上就是一个或者多个等差数列,纸上推一下公式就可以了
#include
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const ll mod = 1e9 + 7;
struct node
{
ll l;
ll r;
ll len;
ll inv;
}que[100005];
ll power(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 inv2 = (mod + 1) / 2;
int main()
{
int n;
sc("%d", &n);
for (int i = 1; i <= n; i++)
{
sc("%lld%lld", &que[i].l, &que[i].r);
que[i].len = que[i].r - que[i].l + 1;
que[i].inv = power(que[i].len, mod - 2);
}
ll ans = 0, ans1 = 1;
for (int i = 1; i <= n; i++)
ans1 = ans1 * que[i].len % mod;
for (int i = 1; i < n; i++)
{
ll t = ans1 * que[i].inv % mod * que[i + 1].inv % mod;
ll l1 = que[i].l, r1 = que[i].r;
ll l2 = que[i + 1].l, r2 = que[i + 1].r;
if (l2 < l1)
{
if (r2 < l1)
{
ans = (ans + que[i].len * que[i + 1].len % mod * t) % mod;
}
else if (r2 <= r1)
{
ans = (ans + que[i].len * (l1 - l2) % mod * t) % mod;
ans = (ans + (r1 - l1 + r1 - r2) * (r2 - l1 + 1) % mod * inv2 % mod * t) % mod;
}
else
{
ans = (ans + (l1 - l2 + r1 - l2) * (r1 - l1 + 1) % mod * inv2 % mod * t) % mod;
}
}
else if (l2 <= r1)
{
if (r2 <= r1)
{
ans = (ans + (r1 - l2 + r1 - r2) * (r2 - l2 + 1) % mod * inv2 % mod * t) % mod;
}
else
{
ans = (ans + (r1 - l2) * (r1 - l2 + 1) % mod * inv2 % mod * t) % mod;
}
}
else
{
}
}
ans = (ans + ans1) % mod;
pr("%lld\n", ans);
}
就是求每条边被用了多少次,实际上就是这条边的两端节点个数的乘积,所以在dfs求出sz之后,每条边的使用次数就是 sz*(n-sz),排个序即可。
#include
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const int MAXN = 1e5 + 5;
struct edge
{
int to;
int nex;
}e[MAXN * 2];
int head[MAXN], tot;
void init()
{
tot = 1;
memset(head, -1, sizeof(head));
}
void add(int a, int b)
{
e[tot] = edge{ b,head[a] };
head[a] = tot++;
}
ll sz[MAXN];
vectorv;
void dfs(int u, int f)
{
sz[u] = 1;
for (int i = head[u]; i + 1; i = e[i].nex)
{
int v = e[i].to;
if (v == f)
continue;
dfs(v, u);
sz[u] += sz[v];
}
}
int main()
{
init();
int n;
sc("%d", &n);
for (int i = 0; i < n - 1; i++)
{
int a, b;
sc("%d%d", &a, &b);
add(a, b); add(b, a);
}
dfs(1, 0);
for (int i = 2; i <= n; i++)
v.push_back(sz[i] * (n - sz[i]));
sort(v.begin(), v.end(), greater());
ll ans = 0;
for (int i = 1; i < n; i++)
{
ans += v[i - 1] * i;
}
pr("%lld\n", ans);
}
签到,从后往前遍历一下就可以了
#include
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
bool book[100005];
int main()
{
int T;
sc("%d", &T);
while (T--)
{
vectorv[30];
int n;
sc("%d", &n);
for (int i = 0; i < n; i++)
{
book[i] = false;
int t;
sc("%d", &t);
v[t].push_back(i);
}
ll cnt = 2;
for (int i = 29; i >= 0; i--)
{
if (v[i].size() >= cnt)
{
for (int j = 0; j < cnt; j++)
book[v[i][j]] = true;
cnt = 0;
break;
}
else
{
int len = v[i].size();
for (int j = 0; j < len; j++)
book[v[i][j]] = true;
cnt -= len;
}
cnt *= 2;
}
if (cnt == 0)
{
for (int i = 0; i < n; i++)
pr("%d", book[i] == true ? 1 : 0);
pr("\n");
}
else
pr("impossible\n");
}
}
枚举后缀,签到
#include
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
char s[1005];
char ans[1005];
int main()
{
sc("%s", s);
int len = strlen(s);
strcpy(ans, s);
for (int i = 1; i < len; i++)
{
if (strcmp(ans, s+i) < 0)
strcpy(ans, s+i);
}
pr("%s", ans);
}
签到
#include
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
ll a[100005];
int main()
{
int n;
sc("%d", &n);
for (int i = 0; i < n; i++)
sc("%lld", &a[i]);
sort(a, a + n);
pr("%lld\n", a[n - 1] - a[0]);
}