2019CCPC江西省赛(重现赛)在hdu进行
据说很简单
因为现场有多个队伍AK
然鹅
我在40分钟内AC两题之后 就卡在概率题 (后来就没做题目emmm)
先放官方题解
然后慢慢补题
嗯!
题目:
https://pan.baidu.com/s/1nYWq8dWcS9csJDXGWTqHmA 提取码: 8pg4 复制这段内容后打开百度网盘手机App,操作更方便哦
题解:
https://pan.baidu.com/s/1bISMx_yH9yb5NJVirZQ61w 提取码: 4kn4 复制这段内容后打开百度网盘手机App,操作更方便哦
目录
K.签到题
F.签到题2
H.数学题
I.签到题3
J.最小公倍数
G.暴力模拟
D.暴力枚举
A.树的重心
解方程
已知 x = a+b y =a-b 求a*b 可以得知 a = (x+y)/2 b = x-a
#include
#include
#include
using namespace std;
int main()
{
int x,y;
int a,b;
scanf("%d%d",&x,&y);
a = (x+y)/2;
b = (x-a);
printf("%d\n",a*b);
return 0;
}
因为只需要 a,v,i,n 四种字母
先判断这四种字母出现的个数
如果本身没有达到存在这四种字母 则不可能构成avin 答案是 0/1
达到四种字母都存在 则再次计算可能出现avin的次数
PS:要注意分子与分母是否可以同分 (取分子分母得到公因子 同时除掉公因子
#include
#include
#include
#include
using namespace std;
int gcd(int a,int b)
{
if (b==0)return a;
return gcd(b,a%b);
}
int a[30];
int main()
{
int t,x=0,y=0,sum=0;
char m;
while (~scanf("%d", &t)) {
getchar();
memset(a, 0, sizeof a);
for (int i = 0; i < t; i++) {
scanf("%c", &m);
a[m - 'a' + 1] ++;
}
for (int i = 1; i <= 26; i++) {
if (a[i] > 0) {
sum =sum+a[i];
}
}
x = a[1]*a[9]*a[14]*a[22];
y = pow(sum,4);
if (x>0)
{
if (gcd(x,y)>1)
printf("%d/%d\n",x/gcd(x,y),y/gcd(x,y));
else printf("%d/%d\n",x,y);
}
else printf("0/1\n");
}
return 0;
}
在【1,n】之间任取一个数 R, 然后在【1,R】中任取一个数得到 L, 得到区间【L1,R1】
再任取一次,得到区间【L2,R2】,求两区间有交集的概率对1e9+7取模
首先 理解什么是逆元 以及如何线性求逆元
参考:https://blog.csdn.net/qq_35416331/article/details/81059747
https://www.cnblogs.com/Judge/p/9383034.html#_label1
https://www.cnblogs.com/chy-2003/p/9656801.html#%E7%BA%BF%E6%80%A7%E6%B1%82%E9%80%86%E5%85%83
题目中的公式推导 参考博文:https://blog.csdn.net/toohandsomeieaseid/article/details/96757205
AC代码
#include
#include
#include
#define ll long long
using namespace std;
const int maxn = 1e6 + 5;
const int p = 1e9 + 7;
ll inv[maxn], sum[maxn];
ll quickpow (ll x, ll y)
{
ll res = x;
ll ans = 1;
while (y) {
if (y & 1) {
ans = (ans * res)%p;
}
res = (res * res)%p;
y = y >> 1;
}
return ans;
}
int main()
{
inv[0] = 1;
inv[1] = 1;
for (int i = 2; i < maxn; i++) {
inv[i] = ((p - p / i) * inv[p % i]) % p;
}
memset(sum, 0, sizeof sum);
for (int i = 1; i <= maxn; i++) {
sum[i] = sum[i - 1] + inv[i];
}
//
// for (int i = 0; i < 10; i++) {
// printf("%lld\n", sum[i]);
// }
int n;
while (~scanf("%d", &n)) {
ll ans = 0;
for (int i = 1; i <= n; i++) {
ll temp = 0;
temp += i * inv[n] % p;
temp = temp * ((sum[n] - sum[i] + p) % p) % p;
temp = (temp % p) * inv[n] % p;
ans = (ans + temp) % p;
}
ans += (3 + n) * quickpow(4 * n, p - 2);
ans %= p;
printf("%lld\n", ans);
}
return 0;
}
下面是我自己写的过程和理解
这道题理解错题目意思 然后一直想不通为啥就WA了
其实是 将第三位小数位进位到前一位 所增加的数之和(可以为负
代码如下:
#include
#include
#include
#include
using namespace std;
int main()
{
int t, a, c;
char b;
while (~scanf("%d", &t)) {
double sum = 0;
for (int i = 0; i < t; i++) {
scanf("%d%c%d", &a, &b, &c);
c = c % 10;
if (c <= 4) {
sum -= 0.001 * c;
} else {
sum += 0.001 * (10-c);
}
}
printf("%.3lf\n", sum);
}
return 0;
}
题目意思:n个工厂和m个工人 给出每个工厂每天能处理的订单数a[i]
问 是否存在一种情况使得 每个工厂每天处理的订单数相同 且所有人都要在工作 (即 没有多余的工人不工作)
存在则输出“Yes”以及每一个工厂的人数
否则 就输出“No”
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
ll a[10005], b[10005];
ll gcd(ll a, ll b)
{
return b ? gcd(b, a % b) : a;
}
int main()
{
int n ;
ll m;
while (~scanf("%d%lld", &n, &m)) {
ll ans = 1, sum = 0;
for (int i = 0; i < n; i++) {
scanf("%lld", &a[i]);
}
ll mm = gcd(a[0], a[1]);
ans = a[0] * a[1] / mm;
for (int i = 2; i < n; i++) {
mm = gcd(ans, a[i]);
ans = ans * a[i] / mm;
}
for (int i = 0; i < n; i++) {
b[i] = ans / a[i];
sum += b[i];
}
// for (int i=0;i
注意:题目中m的范围是 1~ 10^18,而不是1018(辣鸡题面 小声bb
所以要用 long long 保存数据
还有在计算最小公倍数的时候 要注意
是先求出前面的最小公倍数 与后面的数求公约数 再次得到最小公倍数
举个栗子
3 4 6 8 的最小公倍数是24 而不是3 * 4 * 6 * 8
参考:https://www.cnblogs.com/Dup4/p/11223762.html
第一遍读题目没有弄清题意
看了题解才知道是 在一个十字路口,有nn辆东西走向的车,他们会在 a[i] 时刻到达,有m辆南北走向的车,他们会在 b[i] 时刻到达。问需要让m辆南北走向的车整体等待多少秒,使得他们的开始行动之后不会和东西走向的车相撞?
找到可以取到 b[j] - a[i] 不等于 X 的最小值
数据范围都是 1~1000 可以直接暴力枚举
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
ll const mod = 998244353;
int a[2005], b[2005];
int main()
{
int n, m, x;
while (~scanf("%d%d", &n, &m)) {
memset(a, 0, sizeof a);
memset(b, 0, sizeof b);
for (int i = 0; i < n; i++) {
scanf("%d", &x);
a[x] = 1;
}
for (int i = 0; i < m; i++) {
scanf("%d", &b[i]);
}
int p = 0;
for (int i = 0; i < m; i++) {
if (a[b[i] + p] == 1) {
p++;
i = 0;//全部重新判断一遍
}
}
printf("%d\n", p);
}
return 0;
}
我是傻子嘛555 为啥重现赛的时候不好好做题
感觉没有很难啊QAQ
题目大意:
形成 wave 的条件
1)它至少包含两个元素;
2)奇数位置的所有元素都是相同的;
3)偶数位置的所有元素都是相同的;
4)奇数位置的元素与偶数位置的元素不同。
由1)、2)、3) 可以推断出 wave 中含有的数字有且仅有两种
求所给数组中 形成wave 的最长的长度
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
ll const mod = 998244353;
int a[100005], pos[103][100005], num[103];
int main()
{
int n, c;
scanf("%d%d", &n, &c);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
for (int k = 1; k <= n; k++)
for (int i = 1; i <= c; i++) {
if (a[k] == i) {
num[i]++;
pos[i][num[i]] = k;
}
}
int d = 0;
int flag;
for (int i = 1; i < c; i++)
for (int j = i + 1; j <= c; j++) {
if (num[i] > 0 && num[j] > 0) {
int ans = 0, sum = 0;
int m = min(pos[i][1], pos[j][1]);
int mm = max(pos[i][num[i]], pos[j][num[j]]);
if (m == pos[i][1]) {
flag = 1;
for (int k = m; k <= mm; k++) {
if (a[k] == i && flag == 1) {
flag = 0;
sum++;
}
if (a[k] == j && flag == 0) {
flag = 1;
sum++;
}
d = max(d, sum);
}
} else {
flag = 0;
for (int k = m; k <= mm; k++) {
if (a[k] == j && flag == 0) {
flag = 1;
sum++;
}
if (a[k] == i && flag == 1) {
flag = 0;
sum++;
}
d = max(d, sum);
}
}
}
}
printf("%d\n", d);
return 0;
}
因为我不喜欢用数据结构(其实是太菜了不会QAQ
看了别人的题解还是不懂 然后硬算暴力写了一个多小时emmm 终于AC了
我的代码思想就是 把所有数字的位置存起来 然后枚举某两个数字的位置 判断是否间隔着出现 将他们计数取最大值
数组用的比较多 不过本身数据不大 没有炸
参考:https://blog.csdn.net/Ratina/article/details/96753811
暂时不会
留一个坑……
参考:https://www.cnblogs.com/Dup4/p/11223762.html