题目链接

A. Charm Is Not Always Enough

模拟一下就可以了。

#include <bits/stdc++.h>
using namespace std; int T; int main() {
scanf("%d", &T);
while(T --) {
int n, m;
long long ans = 0;
scanf("%d%d", &n, &m);
while(n --) {
int x;
scanf("%d", &x);
x = x % m;
if(x == 0) continue;
ans = ans + 1LL * (m - x);
}
cout << ans << endl;
}
return 0;
}

B. Max and Alexis Plan to Conquer the World

打表。

设比例为$h$,可以发现$x$天之后的数量等于$n$乘上一个关于$h$的某种前缀和。

$h$只有$100$种,可以把每一种的前缀和都计算好,每组数据二分一下即可。

#include <bits/stdc++.h>
using namespace std; double h[105][4500]; void init() {
for(int i = 1; i <= 100; i ++) {
h[i][0] = 1.0;
for(int t = 1; t < 4500; t ++) {
h[i][t] = h[i][t - 1] + h[i][t - 1] * i / 100;
}
//printf("%lf\n", h[i][4499]);
}
} int main() {
init();
int T ;
scanf("%d", &T);
int cas = 1;
while(T -- > 0) {
double n;
scanf("%lf", &n);
int r;
scanf("%d", &r);
double p;
scanf("%lf", &p); int L = 0, R = 4499;
int ans = 0;
while(L <= R) {
int mid = (L + R) / 2;
if(n * h[r][mid] >= p) {
ans = mid;
R = mid - 1;
} else {
L = mid + 1;
}
}
printf("Case %d: %d\n", cas, ans);
cas ++;
}
}

C. Being Common is Too Mainstream

质因数分解,暴力。

#include <bits/stdc++.h>
using namespace std; //****************************************************************
// Miller_Rabin 算法进行素数测试
//速度快,而且可以判断 <2^63的数
//****************************************************************
const int S=20;//随机算法判定次数,S越大,判错概率越小 //计算 (a*b)%c. a,b都是long long的数,直接相乘可能溢出的
// a,b,c <2^63
long long mult_mod(long long a,long long b,long long c)
{
a%=c;
b%=c;
long long ret=0;
while(b)
{
if(b&1){ret+=a;ret%=c;}
a<<=1;
if(a>=c)a%=c;
b>>=1;
}
return ret;
} //计算 x^n %c
long long pow_mod(long long x,long long n,long long mod)//x^n%c
{
if(n==1)return x%mod;
x%=mod;
long long tmp=x;
long long ret=1;
while(n)
{
if(n&1) ret=mult_mod(ret,tmp,mod);
tmp=mult_mod(tmp,tmp,mod);
n>>=1;
}
return ret;
} //以a为基,n-1=x*2^t a^(n-1)=1(mod n) 验证n是不是合数
//一定是合数返回true,不一定返回false
bool check(long long a,long long n,long long x,long long t)
{
long long ret=pow_mod(a,x,n);
long long last=ret;
for(int i=1;i<=t;i++)
{
ret=mult_mod(ret,ret,n);
if(ret==1&&last!=1&&last!=n-1) return true;//合数
last=ret;
}
if(ret!=1) return true;
return false;
} // Miller_Rabin()算法素数判定
//是素数返回true.(可能是伪素数,但概率极小)
//合数返回false; bool Miller_Rabin(long long n)
{
if(n<2)return false;
if(n==2)return true;
if((n&1)==0) return false;//偶数
long long x=n-1;
long long t=0;
while((x&1)==0){x>>=1;t++;}
for(int i=0;i<S;i++)
{
long long a=rand()%(n-1)+1;//rand()需要stdlib.h头文件
if(check(a,n,x,t))
return false;//合数
}
return true;
} //************************************************
//pollard_rho 算法进行质因数分解
//************************************************
long long factor[100];//质因数分解结果(刚返回时是无序的)
int tol;//质因数的个数。数组小标从0开始 long long gcd(long long a,long long b)
{
if(a==0)return 1;//???????
if(a<0) return gcd(-a,b);
while(b)
{
long long t=a%b;
a=b;
b=t;
}
return a;
} long long Pollard_rho(long long x,long long c)
{
long long i=1,k=2;
long long x0=rand()%x;
long long y=x0;
while(1)
{
i++;
x0=(mult_mod(x0,x0,x)+c)%x;
long long d=gcd(y-x0,x);
if(d!=1&&d!=x) return d;
if(y==x0) return x;
if(i==k){y=x0;k+=k;}
}
}
//对n进行素因子分解
void findfac(long long n)
{
if(Miller_Rabin(n))//素数
{
factor[tol++]=n;
return;
}
long long p=n;
while(p>=n)p=Pollard_rho(p,rand()%(n-1)+1);
findfac(p);
findfac(n/p);
} const long long mod = 1000000001LL;
const int maxn = 1e5 + 10;
long long a[maxn];
vector<long long> fac[maxn]; bool prime(long long x) {
if(x == 1) return 0;
for(long long i = 2; i * i <= x; i ++) {
if(x % i == 0) return 0;
}
return 1;
} int main() {
srand(time(NULL));
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i ++) {
scanf("%lld", &a[i]);
}
long long ans = 1;
if(n == 1) {
ans = a[1] % mod;
} else if(n == 2) {
long long g = gcd(a[1], a[2]);
for(int i = 1; i <= n; i ++) {
a[i] /= g;
ans = ans * a[i] % mod;
}
} else if(n == 3) {
long long g;
g = gcd(a[1], gcd(a[2], a[3]));
for(int i = 1; i <= n; i ++) {
a[i] /= g;
}
g = gcd(a[1], a[2]);
a[1] /= g;
a[2] /= g;
g = gcd(a[2], a[3]);
a[2] /= g;
a[3] /= g;
g = gcd(a[1], a[3]);
a[1] /= g;
a[3] /= g;
for(int i = 1; i <= n; i ++) {
ans = ans * a[i] % mod;
}
} else if(n <= 1000) {
for(int i = 1; i <= n; i ++) {
if(a[i] == 1) continue;
tol = 0;
findfac(a[i]);
for(int j = 0; j < tol; j ++) {
fac[i].push_back(factor[j]);
}
}
for(int i = 1; i <= n; i ++) {
for(int j = 0; j < fac[i].size(); j ++) {
if(a[i] % fac[i][j]) continue;
int num = 0;
for(int k = 1; k <= n; k ++) {
if(a[k] % fac[i][j] == 0) num ++;
}
if(num < 2) continue;
for(int k = 1; k <= n; k ++) {
if(a[k] % fac[i][j] == 0) {
a[k] /= fac[i][j];
}
}
}
}
for(int i = 1; i <= n; i ++) {
ans = ans * a[i] % mod;
}
} else {
for(long long x = 2; x <= 601; x ++) {
if(!prime(x)) continue;
while(1) {
int num = 0;
for(int i = 1; i <= n; i ++) {
if(a[i] % x == 0) num ++;
}
if(num < 2) break;
for(int i = 1; i <= n; i ++) {
if(a[i] % x == 0) a[i] /= x;
}
}
}
for(int i = 1; i <= n; i ++) {
ans = ans * a[i] % mod;
}
}
printf("%lld\n", ans);
return 0;
} /*
10
1 2 3 4 5 6 7 8 9 10
*/

D. Shaat Chara

对于第$i$堆石头,要使得拿走第$i$堆的若干颗石头变成必胜态,也就是要使得剩下的所有石头异或和为$0$。

#include <bits/stdc++.h>
using namespace std; const long long mod = 1000000007LL;
const int maxn = 2e5 + 10;
int T, n;
int a[maxn]; int main() {
scanf("%d", &T);
int cas = 1;
while(T --) {
scanf("%d", &n);
int Xor = 0;
for(int i = 1; i <= n; i ++) {
scanf("%d", &a[i]);
Xor = Xor ^ a[i];
}
int ans = 0;
for(int i = 1; i <= n; i ++) {
Xor = Xor ^ a[i];
if(Xor < a[i]) ans ++;
Xor = Xor ^ a[i];
}
printf("Case %d: %d\n", cas ++, ans);
}
return 0;
}

E. Just One Swap

如果每个数字都不一样,答案就是$C_n^2$。

否则,相同的数字交换有$1$种情况,再计算不同数字交换的方案数。

#include <bits/stdc++.h>
using namespace std; const int maxn = 1e5 + 10;
int T;
int a[maxn]; int main() {
scanf("%d", &T);
while(T --) {
memset(a, 0, sizeof a);
int n;
scanf("%d", &n);
int y = n;
while(n --) {
int x;
scanf("%d", &x);
a[x] ++;
}
int ok = 1;
for(int i = 1; i <= 100000; i ++) {
if(a[i] > 1) ok = 0;
} long long ans = 0;
if(ok) {
ans = 1LL * y * (y - 1) / 2;
} else {
ans = 1LL;
long long sum = 0;
for(int i = 1; i <= 100000; i ++) {
ans = ans + sum * a[i];
sum = sum + a[i];
}
}
printf("%lld\n", ans);
}
return 0;
}

F. Halum and Candies

贪心,二分。

这题最直观的做法是每次将最大的$k$个数字减$1$,直到不能操作为止,但是在题目的数据规模下容易超时。

较为容易的写法是二分答案+验证,假设二分到$x$个人,只要看$\sum\limits_{i = 1}^n {\min (a[i],x)}$和$x*k$的大小关系即可。

#include <bits/stdc++.h>
using namespace std; int T, n, k;
const int maxn = 1e5 + 10;
long long a[maxn]; int check(long long x) {
long long p = 0;
for(int i = 1; i <= n; i ++) {
p = p + min(x, a[i]);
}
if(p >= x * k) return 1;
return 0;
} int main() {
int cas = 1;
scanf("%d", &T);
while(T --) {
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; i ++) {
scanf("%lld", &a[i]);
}
long long L = 0;
long long R = 1e12;
long long ans = 0;
while(L <= R) {
long long mid = (L + R) / 2;
if(check(mid)) ans = mid, L = mid + 1;
else R = mid - 1;
}
printf("Case %d: %lld\n", cas ++, ans);
}
return 0;
} /*
3
3 3
1 2 3
3 1
1 2 3
3 2
3 2 4
*/

G. XOR 'em all!

线段树。

每个节点存储每一种$1$的个数的最小的位置,以及转换后的即可。

#include <bits/stdc++.h>
using namespace std; const int maxn = 1e6 + 10;
int T, n, q;
int a[maxn], cnt[2 * maxn];
int s[maxn * 4][2][25];
int p[maxn * 4], f[maxn * 4];
int ans, B, v; int lowbit(int x) {
return x & (-x);
} void init() {
for(int i = 1; i < (1 << 20); i ++) {
cnt[i] = cnt[i - lowbit(i)] + 1;
}
} void pushUp(int rt) {
for(int i = 0; i < 21; i ++) {
s[rt][0][i] = min(s[2 * rt][p[2 * rt]][i],
s[2 * rt + 1][p[2 * rt + 1]][i]);
s[rt][1][i] = min(s[2 * rt][p[2 * rt] ^ 1][i],
s[2 * rt + 1][p[2 * rt + 1] ^ 1][i]);
}
p[rt] = 0;
} void pushDown(int rt) {
if(f[rt] == 0) return;
p[2 * rt] = (p[2 * rt] + f[rt]) % 2;
f[2 * rt] = (f[2 * rt] + f[rt]) % 2;
p[2 * rt + 1] = (p[2 * rt + 1] + f[rt]) % 2;
f[2 * rt + 1] = (f[2 * rt + 1] + f[rt]) % 2;
f[rt] = 0;
} void build(int l, int r, int rt) {
p[rt] = 0;
f[rt] = 0;
if(l == r) {
for(int t = 0; t < 2; t ++) {
for(int i = 0; i < 21; i ++) {
s[rt][t][i] = n + 1;
}
}
s[rt][0][a[l]] = l;
s[rt][1][20 - a[l]] = l;
return;
}
int mid = (l + r) / 2;
build(l, mid, 2 * rt);
build(mid + 1, r, 2 * rt + 1);
pushUp(rt);
} void update(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R) {
p[rt] = (p[rt] + 1) % 2;
f[rt] = (f[rt] + 1) % 2;
return;
}
pushDown(rt);
int mid = (l + r) / 2;
if(L <= mid) update(L, R, l, mid, 2 * rt);
if(R > mid) update(L, R, mid + 1, r, 2 * rt + 1);
pushUp(rt);
} void query(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R) {
for(int i = 0; i < 21; i ++) {
if(s[rt][p[rt]][i] > n) continue;
if(abs(i - v) < B) {
B = abs(i - v);
ans = s[rt][p[rt]][i];
} else if(abs(i - v) == B) {
ans = min(ans, s[rt][p[rt]][i]);
}
}
return;
}
pushDown(rt);
int mid = (l + r) / 2;
if(L <= mid) query(L, R, l, mid, 2 * rt);
if(R > mid) query(L, R, mid + 1, r, 2 * rt + 1);
pushUp(rt);
} int main() {
init();
scanf("%d", &T);
int cas = 1;
while(T --) {
printf("Case %d:\n", cas ++);
scanf("%d%d", &n, &q);
for(int i = 1; i <= n; i ++) {
scanf("%d", &a[i]);
a[i] = cnt[a[i]];
}
build(1, n, 1);
while(q --) {
int op, l, r;
scanf("%d%d%d", &op, &l, &r);
if(op == 1) {
scanf("%d", &v);
v = cnt[v];
B = 100;
ans = n + 1;
query(l, r, 1, n, 1);
printf("%d\n", ans);
} else {
update(l, r, 1, n, 1);
}
}
}
return 0;
} /*
1
10 9
47810 337106 289217 728190 763968 210307 934334 929186 401808 365768
2 8 10
1 2 10 611293
2 2 4
1 1 8 422298
2 6 8
2 2 10
1 5 6 180197
2 7 8
1 4 8 712158
*/

H. Simple Path

树形$dp$。

注意点:这题数据有问题,题面上说每条边都是从$u$到$v$的,但事实上不是。

#include <bits/stdc++.h>
using namespace std; const long long mod = 1000000007LL;
const int maxn = 4e5 + 10;
int T;
int h[maxn];
int v[maxn];
long long w[maxn];
int nx[maxn];
int n;
int sz[maxn];
long long ans;
int cnt;
int f[maxn]; void add(int a, int b, long long c) {
v[cnt] = b;
w[cnt] = c;
nx[cnt] = h[a];
h[a] = cnt ++;
} void SZ(int x) {
sz[x] = 1;
f[x] = 1;
for(int i = h[x]; i != -1; i = nx[i]) {
if(!f[v[i]]) {
SZ(v[i]);
sz[x] += sz[v[i]];
}
}
} void DP(int x, long long sum, int dep) {
f[x] = 1;
for(int i = h[x]; i != -1; i = nx[i]) {
if(f[v[i]]) continue;
// printf(" %d -> %d \n", x, v[i]);
long long A = 1LL * sz[v[i]] * sum % mod;
long long B = 1LL * sz[v[i]] * sz[v[i]] % mod;
B = 1LL * B * dep % mod;
long long C = (A - B + mod) % mod;
C = 1LL * C * w[i] % mod;
// cout << x << " debug " << C << endl;
ans = (ans + C) % mod;
long long G = 1LL * sz[v[i]];
G = (sum + G) % mod;
DP(v[i], G, dep + 1);
} //printf("debug %d %lld\n", x, dp[x]);
} int main() {
scanf("%d", &T);
int cas = 1;
while(T --) {
scanf("%d", &n);
cnt = 0;
for(int i = 1; i <= n; i ++) {
h[i] = -1;
sz[i] = 0;
f[i] = 0;
}
for(int i = 1; i < n; i ++) {
int a, b;
long long c;
scanf("%d%d%lld", &a, &b, &c);
add(a, b, c);
add(b, a, c);
}
SZ(1);
for(int i = 1; i <= n; i ++) {
if(sz[i] <= 0) while(1) {}
}
for(int i = 1; i <= n; i ++) {
f[i] = 0;
}
ans = 0;
DP(1, sz[1], 1);
printf("Case %d: %lld\n", cas ++, ans);
}
return 0;
} /*
2
7
1 2 3
1 3 2
2 4 1
2 5 4
3 6 6
3 7 8 6
1 2 3
1 3 2
1 4 4
3 5 7
3 6 1
*/

2017 Bangladesh National High School Programming Contest ( National Round, Senior Group ), NHSPC 2017 题解的更多相关文章

  1. Codeforces Gym101606 A.Alien Sunset (2017 United Kingdom and Ireland Programming Contest (UKIEPC 2017))

    2017 United Kingdom and Ireland Programming Contest (UKIEPC 2017) 寒假第一次组队训练赛,和学长一起训练,题目难度是3颗星,我和猪队友写 ...

  2. 2017 United Kingdom and Ireland Programming Contest (UKIEPC 2017)

    A. Alien Sunset 暴力枚举答案即可. #include<cstdio> int n,i,mx; struct P{ int h,r,t; bool night(int x){ ...

  3. 2017, X Samara Regional Intercollegiate Programming Contest 题解

    [题目链接] A - Streets of Working Lanterns - 2 首先将每一个括号匹配串进行一次缩减,即串内能匹配掉的就匹配掉,每个串会变成连续的$y$个右括号+连续$z$个左括号 ...

  4. 2019.04.11 第四次训练 【 2017 United Kingdom and Ireland Programming Contest】

    题目链接:  https://codeforces.com/gym/101606 A: ✅ B: C: ✅ D: ✅ https://blog.csdn.net/Cassie_zkq/article/ ...

  5. 2017 Wuhan University Programming Contest (Online Round) Lost in WHU 矩阵快速幂 一个无向图,求从1出发到达n最多经过T条边的方法数,边可以重复经过,到达n之后不可以再离开。

    /** 题目:Lost in WHU 链接:https://oj.ejq.me/problem/26 题意:一个无向图,求从1出发到达n最多经过T条边的方法数,边可以重复经过,到达n之后不可以再离开. ...

  6. 2017 Wuhan University Programming Contest (Online Round) C. Divide by Six 分析+模拟

    /** 题目:C. Divide by Six 链接:https://oj.ejq.me/problem/24 题意:给定一个数,这个数位数达到1e5,可能存在前导0.问为了使这个数是6的倍数,且没有 ...

  7. 2017 Wuhan University Programming Contest (Online Round) B Color 树形dp求染色方法数

    /** 题目:Color 链接:https://oj.ejq.me/problem/23 题意:给定一颗树,将树上的点最多染成m种颜色,有些节点不可以染成某些颜色.相邻节点颜色不同.求染色方法数. 思 ...

  8. [寒假集训第一场]gym101606 2017 United Kingdom and Ireland Programming Contest (UKIEPC 2017)

    3星场 难度在于英文题面太难读懂了QAQ 看样例猜题意的我 博客园的c++主题真丑 A Alien Sunset \(description\) 有\(n\)个星球,每个星球自转时间不一样,所以一天的 ...

  9. Codeforces Gym101606 C.Cued In (2017 United Kingdom and Ireland Programming Contest (UKIEPC 2017))

    C Cued In 这个题是打球的.都忘了写的什么了... 代码: 1 #include<iostream> 2 #include<cstring> 3 #include< ...

随机推荐

  1. 高性能流媒体服务器EasyDarwin

    标准RTSP拉模式直播(EasyRelayModule):适合内部监控 分布式部署(EasyCMSModule):负载均衡主要是用Reids作为负载

  2. bat 批量更改文件名

    通过如下批处理命令可实现批量更改文件名: @echo set DIR="%cd%" echo DIR=%DIR% set /p ext=文件类型: set /p find=要替换内 ...

  3. Java并发编程原理与实战三十:CountDownLatch与CyclicBarrier 区别

    相信每个想深入了解多线程开发的Java开发者都会遇到CountDownLatch和CyclicBarrier,大家也在网上看到各种介绍原理,代码的,以及他们区别(应付面试)的,但是很少能讲清楚:他们到 ...

  4. Kafka消息系统基础知识索引

    一些观念的修正 从 0.9 版本开始,Kafka 的标语已经从“一个高吞吐量,分布式的消息系统”改为"一个分布式流平台". Kafka不仅仅是一个队列,而且是一个存储,有超强的堆积 ...

  5. 标准vim配置文件 带注释(适合C++编译)

    我的vim配置文件,适合大多数人习惯 """""""""""""&qu ...

  6. 苹果手机浏览器$(document).on(“click”,function(){})点击无效的问题

    <label class="js_highlight" style="display: inline-block;float: left;width: 50%;&q ...

  7. 如何在阿里云Centos下安装Nginx

    Nginx("engine x")是一款轻量级的HTTP和反向代理服务器.相比于Apache.lighttpd等,它具有占有内存少.并发能力强.稳定性高等优势.它最常见的用途就是提 ...

  8. Hibernate5笔记6--Hibernate检索优化

    Hibernate检索优化: 检索即查询.为了减轻DB的访问压力,提高检索效率,Hibernate对检索进行了优化. 所谓检索优化,指的是对查询语句的执行时机进行了细致.严格的把控:并不是代码中一出现 ...

  9. SQLServer 学习相关资料整理【转】

    存储过程: SQL Server 存储过程 博客园上的一篇文章,讲解的非常详细,有测试代码,很实用. sqlserver存储过程中执行动态sql语句  The Curse and Blessings ...

  10. ggplot2使用初探

    ggplot2已经成为了R语言中数据可视化的同义词, 这是一个强大的工具, 可以帮助我们制作优良的图表, 创造出令人吃惊的图片, 下面我们一起学习(本博文参考了知乎问题如何使用 ggplot2中黄宝臣 ...