题目链接

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. 《Science》:对年轻科学家的忠告

  2. 【学习笔记】FreeMarker 之于Servlet与Stuts2的应用

    FreeMarker应用在Servlet(0配置web.xml形式): 准备环境: tomcat7.eclipse最新版.jdk1.8.freemarker v2.3.20.jar 举例项目结构图: ...

  3. SVN自动更新-win平台

    把项目给外包做,他们天天整个ftp传来传去,上传一次还要到处翻View和Controller,还有漏传的情况,简直low到不行.看不下去了,就准备整个svn.虽然svn解决了上传的问题,但是自动发布还 ...

  4. iOS设备分辨率

    CHENYILONG Blog iOS设备分辨率 © chenyilong. Powered by Postach.io Blog

  5. 【译】第三篇 Integration Services:增量加载-Adding Rows

    本篇文章是Integration Services系列的第三篇,详细内容请参考原文. 增量加载是什么增量加载仅加载与先前加载差异的.差异包括:->新增的行->更新的行->删除的行通过 ...

  6. MySQL数据记录大小写敏感问题【转】

    MySQL大小写敏感 字符串大小写敏感和Mysql的数据库的名字.表名字.字段名字.还有字段值有关. 1.和数据库名字.表名字.存储过程和触发器有关 为0时:表示区分大小写,使用CREATE TABL ...

  7. jQuery之字体大小的设置

    先获取字体大小,进行处理. 再将修改的值保存. slice() 方法可从已有的数组中返回选定的元素.arrayObject.slice(start,end).start     必需.规定从何处开始选 ...

  8. Nginx1.8.1打开gzip压缩

    1.进入Nginx配置文件目录,打开nginx配置文件 cd /usr/local/src/nginx-1.8.1 vi nginx.conf 2.找到“http {”在之间加入如下配置 gzip o ...

  9. php内存管理机制与垃圾回收机制

    PHP内存管理机制 1 var_dump(memory_get_usage()); //获取内存 2 $a = "laruence"; //定义一个变量 3 var_dump(me ...

  10. Linux下LAMP服务器的搭建

    1.安装并配置Apache 安装apache的方法有很多种,这里选择通过yum方式进行安装,但需要Linux系统能够连接互联网,执行如下命令,安装Apache. # yum install httpd ...