A - Secret of Chocolate Poles
dbq,我没想到dp,我还在找规律,组合数之类的
一看就会,一做就废
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const int maxn = 20;
ll dp[150][3], k, l;
int main() {
cin >> l >> k;
dp[1][1] = 1;
if (l >= k) dp[k][1] = 1;
for (int i = 1;i < l;i++) {
dp[i + 1][0] += dp[i][1];
dp[i + 1][1] += dp[i][0];
if (i + k <= l) {
dp[i + k][1] += dp[i][0];
}
}
ll ans = 0;
for (int i = 1;i <= l;i++) {
ans += dp[i][1];
}
cout << ans << endl;
return 0;
}
B - Parallel Lines
计算几何,不是我写的
DFS 明天补叭
C - Medical Checkup
没开longlong挂了好多次
#include
#include
#include
#include
#include
#include
#include
#include
#define inf 2e9
using namespace std;
const int maxn = 1e5 + 5;
int a[maxn],n,ans[maxn];
long long t;
int main() {
cin >> n >> t;
for (int i = 1;i <= n;i++)cin >> a[i];
int cur_record = a[1];
long long cur_sum = 0;
for (int i = 1;i <= n;i++) {
cur_sum += a[i];
cur_record = max(cur_record, a[i]);
//i开始往前排队的时候,最慢的人已经排到的位置
//+pos(1)
long long pos = 1;
if(t >= cur_sum)
pos = long long((t - cur_sum)/cur_record + 2);
cout << pos << endl;
}
return 0;
}
学了差分数组(一直被这个名字劝退,真的好奇怪)
差分数组
f[i]=a[i]-a[i-1],那么每个数组元素a[i]=f[1]+f[2]+…+f[i]=a[1]+a[2]-a[1]+a[3]-a[2]+…a[i]-a[i-1] = a[i]
通过差分数组可以求前缀和 sum[i]=a[1]+a[2]+…+a[i] = f[1]+ f[1]+f[2]+f[1]+f[2]+f[3]+…=(i)f[1]+(i-1)f[2]+…+f[i] = sigma_k=1 ^(i) (i-k+1) * f[k];
用途:
差分数组可以快速处理区间加减操作和前缀和。
先熟悉一下
洛谷P3948 第一次在洛谷见到这么多数据的题hh
差分模板题
#include"pch.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
#define sz sizeof
#define mk make_pair
using namespace std;
long long n, opt, minn, maxn,mod;
long long f[100005],p[100005];
long long work(long long l, long long r) {
long long res = 0,t=0;
//求出a[l-1]的值
for (int i = 1;i < l;i++) {
t += f[i];
}
for (int i = l;i <= r;i++) {
t += f[i];//L_R真实区间中的每一个值
if (t *i%mod >= minn && t * i%mod <= maxn) {
res++;
}
}
return res;
}
void prepare() {
long long tmp=0, t = 0;
bool flag = false;
for (int i = 1;i <= n;i++) {
t += f[i];
flag = false;
if (t*i%mod >= minn && t*i%mod <= maxn) {
flag = true;
}
p[i] = p[i - 1] + flag;
}
return;
}
int main() {
cin >> n >> opt >> mod >> minn >> maxn;
for (int i = 1;i <= opt;i++) {
char a;cin >> a;
long long l, r;
if (a == 'A') {
long long x; cin >> l >> r >> x;
f[l] += x;f[r+1] -= x;
}
else {
cin >> l >> r;
long long ans = work(l, r);
cout << ans << endl;
}
}
long long fia;cin >> fia;
prepare();
for (int i = 1;i <= fia;i++) {
long long l, r;cin >> l >> r;
cout << p[r] - p[l-1] << endl;
}
return 0;
}
补题
I Starting a Scenic Railroad Service
两种策略:
1.自由选择-由于选择顺序不确定
ans1:代表最差情况,是区间相交数的最大值。
玄妙的结论:
与一个区间相交的区间个数 = 右端点前左端点的个数 - 左端点前右端点的个数
好神奇啊啊啊啊啊啊啊啊啊啊这样相离的会被消掉诶 好东西,MARK
2.安排-是使得座位数最少的最优策略
所求ans2是指某个时刻(车站)上人数的最大值,
用区间代表,也就是区间存在重叠时,这些人同时在车站。(下面是废话,一波解释)
这种情况,不能够通过安排座位减少座位总数。(使用sum数组表示人数,
记录一个旅客的起点、终点时,使用差分数组操作;求解时先复原数组,直接求最大值即可)
所以:ans1=max(与区间i交叉的区间个数总和)(i=1,2,…n) //每个站的区间交叉最大值
ans2 =max(sum[i]) //每个站 的人数 最大值
代码还在running,可我已经感觉被掏空orz 再失眠会死吗1551
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
#define sz sizeof
using namespace std;
const int maxn = 2e5 + 10;
int n,ans1,ans2;
struct Line {
int L, R;
}l[maxn];
//记录起点个数,终点个数,人数
int st[maxn], ed[maxn], sum[maxn];
int main() {
cin.tie(0);
ios::sync_with_stdio(0);
cin >> n;
for (int i = 1;i <= n;i++) {
cin >> l[i].L >> l[i].R;
//计数操作,就不要遍历了 这就是差分数组的好处
st[l[i].L]++; ed[l[i].R]++;
//这里就是--的操作 因为这里是左闭右开,所以不用+1
sum[l[i].L]++;sum[l[i].R]--;
}
//恢复原数组
for (int i = 1;i <= maxn;i++) {
st[i] += st[i - 1];
ed[i] += ed[i - 1];
sum[i] += sum[i - 1];
}
for (int i = 1;i <= n;i++) {
//右端点前面左端点的个数-左端点前右端点的个数
ans1 = max(ans1, st[l[i].R-1] - ed[l[i].L]);
}
for (int i = 1;i < maxn;i++) {
ans2 = max(ans2, sum[i]);
}
cout << ans1 << " " << ans2 << endl;
return 0;
}
F - Pizza Delivery
图论 都是dalao,佩服佩服
4.5 周末练习
好的,我又忘了补题 \ · w · / orz
这周天天开车终于把科目三考完了,连梦里都在踩刹车,真想一脚油门送自己上天
终于搞完了,可以安心水题了(bushi 落下那么多课诶 我咋整哦
H-Lexical Sign Sequence
线段树+贪心(因为要字典序小,所以能放-1就放-1,如果不行就改成1,以及改成1的时候从右往左 因为要字典序最小
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
//#include
#define INF 0x3f3f3f3f
#define sz sizeof
using namespace std;
const int maxn = 1e5 + 5;
int n, k,ans[maxn];
bool vis[maxn], ok = 1;
struct Q {
int l, r, s;
bool operator < (Q &q) {
if (r != q.r) return r < q.r;
return l < q.l;
}
}q[maxn];
int T[maxn << 2];
//Build
void Build(int rt,int l, int r) {
if (l == r) {
T[rt] = ans[l];
return;
}
int mid = (l + r) >> 1;
Build(rt << 1, l, mid);
Build(rt << 1 | 1, mid + 1, r);
T[rt] = T[rt << 1] + T[rt << 1 | 1];
}
//线段树查询
int Cal(int rt, int l, int r, int L, int R) {
if (L <= l && R >= r) return T[rt];
int mid = (l + r) >> 1;
if (R <= mid)
return Cal(rt << 1, l, mid, L, R);
else if (L > mid)
return Cal(rt << 1 | 1, mid + 1, r, L, R);
else
return Cal(rt << 1, l, mid, L, R) + Cal(rt << 1 | 1, mid + 1, r, L, R);
}
//线段树更新
void Update(int rt, int l, int r, int x,int w) {
if (l == r) {
T[rt] = w;
return;
}
int mid = (l + r) >> 1;
if (x <= mid)
Update(rt << 1, l, mid, x, w);
else
Update(rt << 1 | 1, mid + 1, r, x, w);
T[rt] = T[rt << 1] + T[rt << 1 | 1];
}
void print() {
if (!ok) {
cout << "Impossible" << endl;
return;
}
for (int i = 1;i <= n;i++) {
cout << ans[i] << " ";
}
cout << endl;
}
int main() {
cin.tie(0);ios::sync_with_stdio(0);
cin >> n >> k;
for (int i = 1;i <= n;i++) {
cin >> ans[i];
if (ans[i] != 0) {
vis[i] = 1;
}
else ans[i] = -1;
}
for (int i = 1;i <= k;i++) {
cin >> q[i].l >> q[i].r >> q[i].s;
}
sort(q + 1, q + 1 + k);
Build(1, 1, n);
for (int i = 1;i <= k && ok;i++) {
//cout << q[i].r << " ";
int now = Cal(1,1,n,q[i].l, q[i].r);
if (now >= q[i].s) {
// cout << "now = " << now << " >= " << q[i].s << endl;
continue;
}
else {
int d = q[i].s - now;
// cout << "NOT OK"<
int L = q[i].l, R =q[i].r;
while (d > 0 && L <= R) {
if (!vis[R]) {
vis[R] = 1;
ans[R] = 1;
Update(1, 1, n, R, 1);
d -= 2;
}
R--;
}
if (d >0) {
ok = 0;
break;
}
}
}
print();
return 0;
}
I - Lie Detector
签到,但是一开始没敲出来 …
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
#define sz sizeof
#define mk make_pair
using namespace std;
const int maxn = 1e5 + 5;
int n;
string s[maxn];
int main() {
cin >> n;
for (int i = 1;i <= n;i++) cin >> s[i];
bool f = 1;
for (int i = n;i >= 2;i--) {
if (f) {
if (s[i] == "TRUTH")
f = 0;
}
else {
if (s[i] == "LIE")
f = 1;
}
}
string ans;
if (f) ans = s[1];
else {
if (s[1] == "TRUTH") ans = "LIE";
else ans = "TRUTH";
}
cout << ans << endl;
return 0;
}
J -Future Generation
dp(代码非原创 来自dalao)
因为数据范围小(2 ^ 16),枚举所有子串
设dp[i][j] = 考虑到第i个字符串中第j大子序列时的max_ans
状态转移方程:
dp[i][j]=max(dp[i][j-1],dp[i-1][k-1]+len[i][j])
其中k是第i-1个字符串中第一个 >= str[i]j的序号,那么k-1就是第i-1个字符串中最后一个<=str[i][j]的序号
len[i][j]为第i个字符串的第j个子序列的长度。
其中需要注意的几点:
(1)str[i][j]存第i个字符串的第j个子序列
需要使用sort
(2)len[i][j]第i个字符串的第j个子序列长度
(3)预处理:dp[1][1的所有字串个数]
dp[1][i]=max(dp[1][i-1],len[1][i])
(4)状态转移时处理k越界的情况
k =
#include
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const int maxn = 5e5 + 5,inf = 0x3f3f3f3f;
int n;
string s[20];
vector<string> str[20];
ll dp[20][1 << 16];
int main() {
cin >> n;
for (int i = 1;i <= n;i++) {
cin >> s[i];
str[i].push_back("");
//生成的是子序列而不是子串,
//这是一个类似暴力求所有子序列的过程
for (int j = 0;j < s[i].length();j++) {
int len = str[i].size();
//在已知所有的子序列后+当前字符, 生成新的子序列
for (int k = 0;k < len;k++) {
str[i].push_back(str[i][k] + s[i][j]);
}
}
sort(str[i].begin(), str[i].end());
}
memset(dp, -inf, sizeof(dp));
for (int i = 1;i < str[1].size();i++) {
dp[1][i] = max(dp[1][i - 1], (ll)str[1][i].size());
}
for (int i = 2;i <= n;i++) {
int limit = str[i - 1].size(), k = 0;;
for (int j = 1;j < str[i].size();j++) {
while (k < limit && str[i - 1][k] < str[i][j]) k++;
dp[i][j] = max(dp[i][j - 1], dp[i - 1][k - 1] + (ll)str[i][j].size());
}
}
int len = str[n].size();
ll ans = dp[n][len - 1];
if (ans < 0) cout << -1 << endl;
else cout << ans << endl;
return 0;
}
L - Binary String
题意:给出两个数n,k,问n的二进制表示中取出多少个数字之后新数n’小于等于k.
(1)解法一
思想是贪心,优先删去高位1然后不停检查
需要注意的是(其实并不需要特别注意,只是我比较菜而已
我们需要记录去除1的前面的部分代表的数字,当去除一位后,
设s为原数字,s-=2^(位数-1); s-=(高位和)/2
因为前面部分位数降低了,后面部分没变,这一位消失了。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
//#include
#define INF 0x3f3f3f3f
#define sz sizeof
using namespace std;
const int maxn = 1e5 + 5;
long long n,ss,tot,up;
bool f = 0;
string s;
long long mypow(int b) {
if (b == 0) return 1;
long long res = 1;
return res << b;
}
long long getnum(string s) {
long long res = 0;
for (int i = 0;i < s.length();i++) {
//1才算啊。。。
if (s[i] == '1') {
res += mypow(s.length() - i - 1);
}
}
return res;
}
int main() {
cin >> n >> s;
ss = getnum(s);
up = mypow(s.length() - 1);
for (int i = 1;i < s.length();i++) {
if (ss <= n)break;
if (s[i] == '1') {
//将这一位的1删去
//这一位前面的数字和 位数下降1
ss -= mypow(s.length() - i - 1);
ss -= up / 2;
up >>= 1;
tot++;
}
}
//删0
while (ss > n) {
ss >>= 1;
tot++;
}
cout << tot << endl;
return 0;
}
(2)分类讨论
是原来的想法,类似于构造
仔细重做了,原来还是贪心,记得开longlong
#include
#include
#include
#include
#include
#include
#include
using namespace std;
long long a[65];
int b[65];
long long quickpow(long long a, long long b)
{
long long res = 1;
while (b)
{
if (b & 1) res = res * a;
a *= a;
b >>= 1;
}
return res;
}
string s,nn;
long long ss,n;
int ls,ln, cnt0_n, cnt0_s,ans;
long long getnum(string s) {
int l = s.length();
long long res = 0;
for (int i = l - 1;i >= 0;i--) {
if (s[i] == '1'){
res += quickpow(2,l-i-1);
}
else cnt0_s++;
}
return res;
}
void process(long long n) {
while (n) {
if (n%2 == 0){
cnt0_n++;
}
nn+=char(n % 2+'0');
n /= 2;
}
reverse(nn.begin(), nn.end());
}
int main(){
cin >> n >> s;
ss = getnum(s);
if (ss <= n) {
ans = 0;
}
else {
process(n);
ls = s.length();ln = nn.length();
ans = ls - ln;
if (cnt0_s +1 < ln) {
int now = cnt0_s + 1,bit=0;
//1000000000000
long long test = quickpow(2, ln - 1);
//cout << test << endl;
for (int i = ls - 1;i >= 0 && now<ln;i--) {
if (s[i] == '1') {
test += quickpow(2, bit);
now++;
if (test > n) break;
}
bit++;
//cout << i << endl;
}
if (test > n) { ans++;
//cout << test << endl;
}
}
}
cout << ans << endl;
return 0;
}
4.12 练习
Problem A Secret of Chocolate Poles
签到&模拟
//A
#include
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const int maxn = 5e3 + 5,inf = 0x3f3f3f3f;
int n;
struct B {
int a, b, m;
}book[maxn];
struct P {
int id, m;
bool operator<(P & p) {
return m < p.m;
}
}p[maxn];
int a[maxn],b[maxn];
int cnt = 0;
int main() {
cin >> n;
for (int i = 1;i <= n;i++) {
int x;
cin >> x;
p[i].id = i;
p[i].m = x;
}
for (int i = 1;i <= n;i++) {
int x;cin >> x;
p[i].m = x - p[i].m;
}
int cur = n;
sort(p + 1, p + 1 + n);
for (int i = 1;i <= n;i++) {
//cout << p[i].m << " ";
while (p[i].m < 0) {
//cout << "?"<
if (p[cur].m + p[i].m > 0) {
book[++cnt].a = p[i].id;
book[cnt].b = p[cur].id;
book[cnt].m = -p[i].m;
//cout << book[cnt].a << " & " << book[cnt].b << endl;
p[cur].m += p[i].m;
p[i].m = 0;
//cout << p[cur].m << " !!!" << endl;
}
else {
book[++cnt].a = p[i].id;
book[cnt].b = p[cur].id;
book[cnt].m = p[cur].m;
//cout << book[cnt].a << " & " << book[cnt].b << endl;
p[i].m += p[cur].m;
p[cur].m = 0;
cur--;
//cout <<"cur " <
}
}
}
for (int i = 1;i <= cnt;i++){
cout << book[i].a << " " << book[i].b << " "<<book[i].m << endl;
}
return 0;
}
G - Task distributor
答案在T-2T之间,1-T中有T-1/K个会被K整除(正好T%k==0时不算,此时可以满足并行要求)
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const int maxn = 5e3 + 5, inf = 0x3f3f3f3f;
int main() {
long long t, k;
cin >> t >> k;
cout << long long(t + (t-1)/k+1) << endl;
return 0;
}
C- Keys assignment
是模拟页面替换算法吗qwq
记得当时又是个best solution,但没仔细听
乱搞了一个贪心然后失败了,我以为替换掉后续出现次数最小的页面呢,然而好像不一定,应该是根据下一个相同页面出现的位置判断是否替换的。
利用了set集合自带的排序功能,用了类似链式前向星的记录操作。
代码非原创,来自其他dalao,队友写的没看懂我tcl
还有线段树做法,也是类似思路,线段树是用来方便修改维护下一个相同页面出现位置的(好像)
另外,今天发生了一件鬼畜的事情,划水蹭课混了一个通选的大作业,竟然99分1551,可惜我没报这个课啊…
倒是没心没肺不觉得亏,毕竟没认真学,想来上学期那个低分通选倒是亏的很qwq
我怎么写起日记来了??拍飞我自己
//代码来自楼上
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
#define sz sizeof
#define mk make_pair
using namespace std;
const int maxn = 1e5 + 5;
int n, k, ans;
int a[maxn],nxt[maxn], last[maxn];
set<pair<int, int> > st;
int main() {
cin >> n >> k;
for (int i = 1;i <= n;i++) {
cin >> a[i];
}
for (int i = 0;i < maxn;i++) {
last[i] = n + 1;
}
for (int i = n;i >= 1;i--) {
//链、链式前向星?
//倒序
nxt[i] = last[a[i]];
last[a[i]] = i;
}
for (int i = 1;i <= n;i++) {
if (st.count({ i,a[i] }))
st.erase({ i,a[i] });
else {
ans++;
if (int(st.size() == k))
st.erase(*st.rbegin());
}
st.insert({ nxt[i],a[i] });
}
cout << ans << endl;
return 0;
}
E- Test variants
一个似曾相识的构造题
敲了一遍,不懂
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
#define sz sizeof
#define mk make_pair
#define ll long long
using namespace std;
const int maxn = 1e5 + 5;
int n, k,ans[maxn];
int main() {
cin >> n >> k;
int num = (n - 1) / k + 1;
if (k == 1) {
for (int i = 1;i <= n;i++) {
cout << i << endl;
}
}
else{
if ( num ==1 || num <= 2 &&k % 2) {
for (int i = 1;i <= n;i++)
ans[i] = (i & 1);
}
else {
for (int i = 1;i <= k;i++) {
ans[i++] = 0;
ans[i++] = 2;
}
for (int i = k + 1;i <= n;i++) {
ans[i] = (ans[i - k] + 1) % num;
}
for (int i = 1;i <= n;i++) {
cout << ans[i] + 1 << endl;
}
}
}
return 0;
}
I - Key brute forcing
DFS 搜搜搜(代码来自dalao
我觉得这思路有点难想啊,一开始从已知的片段出发,纠结在开头结尾重复的情况,觉得ans*=2,搜一半就好了,后来发现不仅可以从头、从尾扩展,还可以同时从两边拓展,然后就扑街了。
后来发现可以把思维倒过来,遍历所有的可能,(数据小),然后check他们是否满足了题目所给的条件,真的很暴力
就ok了,记得记录长度,要求大于等于2
test7就是检查这个特判的,建议加入特判,或者在dfs里面加上长度的记录。
不过特判比较快
//F
//DFS
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const int maxn = 5e3 + 5, inf = 0x3f3f3f3f;
int n, vis[maxn];
int ok[10][10], cur[10][10];
ll ans = 0;
void inimap() {
for (int i = 1;i <= 9;i++) {
for (int j = 1;j <= 9;j++) {
if (i != j) ok[i][j] = 1;
}
}
ok[1][3] = ok[3][1] = ok[4][6] = ok[6][4] = 0;
ok[7][9] = ok[9][7] = ok[1][7] = ok[7][1] = 0;
ok[2][8] = ok[8][2] = ok[3][9] = ok[9][3] = 0;
ok[1][9] = ok[9][1] = ok[3][7] = ok[7][3] = 0;
return;
}
void dfs(int x, int cnt,int len) {
vis[x] = 1;
//当所有给出条件都用上,答案++
if (cnt == n && len>=2) ans++;
for (int i = 1;i <= 9;i++) {
if (ok[i][x] && !vis[i]) {
dfs(i, cnt + cur[i][x],len+1);
}
}
vis[x] = 0;
}
int main() {
cin >> n;
for (int i = 1;i <= n;i++) {
int a, b;
cin >> a >> b;
cur[a][b] = cur[b][a] = 1;
}
inimap();
//遍历起点,因为用vis标记过,所以不会有重复
for (int i = 1;i <= 9;i++) {
dfs(i, 0,1);
}
cout << ans<< endl;
return 0;
}
K - Forbidden messenger
(1)是模拟+特判的方法,比较难想
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const int maxn = 20;
int x,a,b;
int main() {
cin >> x >> a >> b;
x *= 60;
int ans = 0;
if(a<=b)
ans = (x - a) / b;
else {
ans = (x - a) / a;
//如果在写最后一封没有寄出的信时
//时间还够一封信到达,ans++
if ((x - a) % a >= b) ans++;
}
cout << ans << endl;
return 0;
}
(2) 不等式
分情况讨论1:写信a<寄信b
a+mb <= x
分情况讨论2:a > = b
b+ma <= x
4.19周日训练
B Counting Inversion
错误代码大赏
妄想使用归并排序暴力计算逆序数失败(显然是失败的
//qqq
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
#define sz sizeof
#define mk make_pair
#define ll long long
using namespace std;
const int maxn = 1e6 + 5, mod = 1e7 + 7;;
ll x, y;
int T;
ll ans = 0, book[maxn];
int a[20], b[20];
void merge_sort(int l, int r) {
if (r - l > 0) {
int mid = (l + r) / 2;
int i = l; //辅助数组的下标
int p = l, q = mid + 1;
merge_sort(l, mid);
merge_sort(mid + 1, r);
//printf("%d-%d %d-%d\n",p,mid ,q ,r);
while (p <= mid || q <= r)//左右两部分只要有一部分不为空
{
if (q > r || (p <= mid && a[p] <= a[q]))//从左半数组复制到辅助数组
b[i++] = a[p++];
else {
b[i++] = a[q++];
ans += mid - p + 1;//将逆序对的个数累加起来
}
}
for (i = l; i <= r; i++)//将b中排好序的元素复制到a中
a[i] = b[i];
}
}
void cal(ll x, ll last) {
if (book[x]) {
ans += book[x];
return;
}
int tot = 0;
while (x) {
int tmp = x % 10;
a[tot++] = tmp;
x /= 10;
}
merge_sort(0, tot - 1);
book[x] = ans - last;
}
int main() {
scanf_s("%d", &T);
for (int k = 1;k <= T;k++) {
scanf_s("%lld %lld", &x, &y);
ans = 0;
cout << "Case " << k << ": ";
for (long long i = x;i <= y;i++) {
cal(i, ans);
}
printf("%lld\n", ans);
}
return 0;
}
© Divisors of the Divisors of An Integer
n!= p1^k1 * p2^k2 *…
质因数分解后,计算每个因数的因子个数(也就是套娃
若质因子p为k次方
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
#define sz sizeof
#define mk make_pair
#define ll long long
using namespace std;
const int maxn = 1e6 + 5, mod = 1e7 + 7;;
int n;
int notp[maxn],p[maxn],tot;
ll ans = 0;
void ini() {
//筛出并记录质数,模板
for (int i = 2;i <= maxn;i++) {
if (!notp[i]) {
p[++tot] = i;
}
for (int k = 1;k <= tot && i*p[k] <= maxn;k++) {
notp[p[k] * i] = true;
if (i%p[k] == 0) break;
}
}
}
int main() {
ini();
while (cin >> n && n) {
ans = 1;
for (int k = 1; k <= tot && p[k] <= n;k++) {
int nn = n;
ll tmp = 0;
//求p_n ^{?}
while (nn) {
tmp+=nn/p[k];
nn /= p[k];
}
//因子个数可在(0~t)之间
tmp = ((tmp + 1)*(tmp + 2)/2) % mod;
ans = (ans * tmp) % mod;
}
cout << ans << endl;
}
return 0;
}
在队友的启发下大概了解了下母函数的概念,确实很神奇
链接一下 母函数
可以用来解决多项式乘法这样的问题,把组合转变成乘法(多项式乘法)
E Helping the HR
模拟,orz 原来可以直接用scanf读数字,我orz了 我好垃圾
我还写了字符串处理
//qqq
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
#define sz sizeof
#define mk make_pair
#define ll long long
using namespace std;
const int N = 1e5 + 5, mod = 1e7 + 7;
int n,tmp[8];
int cal(int h, int m, int s) {
return s + m * 60 + h * 3600;
}
bool islate(string s,int r) {
int t = 0;
if (r == 8) t = 9;else t = 12;
if(cal(tmp[1],tmp[2],tmp[3]) > cal(t,30,0))
return 1;
return 0;
}
bool ORZ(string s,int r) {
int h1=tmp[1], m1=tmp[2], s1=tmp[3], h2=tmp[4], m2=tmp[5], s2=tmp[6];
if (cal(tmp[1], tmp[2], tmp[3]) < cal(8, 30, 0)) {
h1 = 8;m1 = 30;s1 = 0;
}
if (cal(h2, m2, s2) - cal(h1, m1, s1) < r * 3600) return 1;
return 0;
}
int main() {
while (cin >> n && n) {
int cnt = 0;
for (int i = 1;i <= n;i++) {
int require = 8;bool GG = 0;
string s;cin >> s;
s.append(":");
int cur_len = 0, cur_tot = 0, j = 2;
int a =0, b = -1;
while (j < s.length()) {
if (s[j] == ':') {
tmp[++cur_tot] = a * 10 + b;
a = 0; b = -1;
}
else {
if (b==-1) b = s[j] - '0';
else {
a = b;
b = s[j] - '0';
}
}
j++;
}
if (s[0] != 'D') require++;
if (islate(s, require) || ORZ(s, require)) {
cnt++;
}
}
if (cnt > 3)
cout << "Issue Show Cause Letter" << endl;
else if (cnt == 0)
cout << "All OK" << endl;
else
cout << cnt << " Point(s) Deducted" << endl;
}
return 0;
}
F Path Intersection
挂了
错误代码实例
//qqq
#include "pch.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
#define sz sizeof
#define mk make_pair
#define ll long long
using namespace std;
const int N = 1e4 + 5, mod = 1e7 + 7;
int n, q, t, k,tot, head[N], f[N][50], d[N];
struct Edge {
int to, next;
}e[2 * N];
void add(int x, int y) {
e[++tot].to = y, e[tot].next = head[x], head[x] = tot;
}
void ini() {
tot = 1;
memset(head, 0, sizeof(head));
memset(f, 0, sizeof(f));
memset(d, 0, sizeof(d));
}
void dfs(int x, int fa) {
f[x][0] = fa;
for (int i = 1; (1 << i) <= d[x]; i++)
f[x][i] = f[f[x][i - 1]][i - 1];
for (int i = head[x]; i; i = e[i].next) {
int y = e[i].to;
if (y == fa) continue;
d[y] = d[x] + 1; dfs(y, x);
}
}
int lca(int x, int y) {
if (d[x] > d[y]) swap(x, y);
for (int i = t; i >= 0; i--)
if (d[f[y][i]] >= d[x]) y = f[y][i];
if (x == y) return x;
for (int i = t; i >= 0; i--)
if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
int T,ans,x[66];
int main(){
scanf_s("%d", &T);
for (int kk = 1;kk <= T;kk++) {
cout << "Case " << kk << ":" << endl;
scanf_s("%d", &n);ini();
t = (int)(log(n) / log(2)) + 1;
for(int i=1;i<n;i++){
int a, b; scanf_s("%d%d", &a, &b);
add(a, b); add(b, a);
}
dfs(1, 0);
scanf_s("%d", &q);
for (int i = 1;i <= q;i++) {
scanf_s("%d", &k);
//两条a,b|c,d
int a, b, c, D; scanf_s("%d%d%d%d", &a, &b, &c, &D);
x[1] = lca(a, c), x[2] = lca(a, D);
x[3] = lca(b, c), x[4] = lca(b, D);
int p1 = 0, p2 = 0;
for (int j = 1;j <= 4;j++) {
if (d[x[j]] > d[p1])
p2 = p1, p1 = x[j];
else if (d[x[j]] > d[p2])
p2 = x[j];
}
//p1,p2是x1-4中最深的两个点
int h1 = lca(a, b), h2 = lca(c, D);
if (p1 == p2) {
if (d[p1] < d[h1] || d[p1] < d[h2])
p1=p2=0;
}
for (int j = 1;j <= k-2 && p1!=0;j++) {
// p1,p2 | c,D
int c, D; scanf_s("%d%d", &c, &D);
x[1] = lca(p1, c), x[2] = lca(p1, D);
x[3] = lca(p2, c), x[4] = lca(p2, D);
int t1=0, t2 = 0;
//cout << x[1] << ", " << x[2] << ", " << x[3] << ", " << x[4] << endl;
for (int j = 1;j <= 4;j++) {
if (d[x[j]] > d[t1])
t2 = t1, t1 = x[j];
else if (d[x[j]] > d[t2])
t2 = x[j];
}
int h1 = lca(p1, p2), h2 = lca(c, D);
if (t1 == t2) {
if (d[t1] < d[h1] || d[t1] < d[h2])
t1 = t2 = 0;
}
p1 = t1, p2 = t2;
//cout << p1 << " " << p2 << endl;
}
//cout << p1 << " & " << p2 << endl;
if (p1 == 0) ans = 0;
else ans = d[p1] + d[p2] - 2 * d[lca(p1, p2)] + 1;
cout << ans << endl;
}
}
return 0;
}
正确代码 我知道了,是sort的时候错了(按depth排序)
(a, b)(c, d)四点的交叉部分是连续的,记录起点与终点,
最后就可以求出路径上的点的个数
num = d[u] + d[v] - 2*d[lca(u,v)]
//qqq
#include "pch.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
#define sz sizeof
#define mk make_pair
#define ll long long
using namespace std;
const int N = 1e5 + 5, mod = 1e7 + 7;
int n, q, t, k, tot, head[N], f[N][50], d[N];
int lg[N];
struct Edge {
int to, next;
}e[2 * N];
void add(int x, int y) {
e[++tot].to = y, e[tot].next = head[x], head[x] = tot;
}
void ini() {
tot = 1;
memset(head, 0, sizeof(head));
memset(f, -1, sizeof(f));
memset(d, 0, sizeof(d));
}
void dfs(int x, int fa) {
d[x] = d[fa] + 1;
f[x][0] = fa;
for (int i = 1; (1 << i) <= d[x]; i++)
f[x][i] = f[f[x][i - 1]][i - 1];
for (int i = head[x]; i; i = e[i].next) {
if (e[i].to != fa)
dfs(e[i].to, x);
}
}
bool cmp(int a, int b) {
return d[a] > d[b];
}
int lca(int x, int y) {
if (d[x] < d[y]) swap(x, y);
while (d[x] > d[y]) {
x = f[x][lg[d[x] - d[y]] - 1];
}
if (x == y) return x;
for (int i = t; i >= 0; i--)
if (f[x][i] != f[y][i])
x = f[x][i], y = f[y][i];
return f[x][0];
}
int T, ans, x[66];
int main() {
scanf_s("%d", &T);
for (int kk = 1;kk <= T;kk++)
{
cout << "Case " << kk << ":" << endl;
scanf_s("%d", &n);ini();
t = (int)(log(n) / log(2)) + 1;
for (int i = 1;i < n;i++) {
int a, b; scanf_s("%d%d", &a, &b);
add(a, b); add(b, a);
}
dfs(1, 0);
for (int i = 1;i <= n;i++) {
lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
}
scanf_s("%d", &q);
int tmp[5];
for (int i = 1;i <= q;i++) {
scanf_s("%d", &k);
//两条a,b|c,d
bool f = 0;
int a, b, c, D;scanf_s("%d%d", &a, &b);
for (int j = 1;j <= k - 1 && !f;j++) {
scanf_s("%d%d", &c, &D);
tmp[1] = lca(a, c);
tmp[2] = lca(a, D);
tmp[3] = lca(b, c);
tmp[4] = lca(b, D);
sort(tmp + 1, tmp + 5,cmp);
// cout << tmp[1] << " & " << tmp[2] << endl;
if (tmp[1] == tmp[2] && (d[lca(a, b)] > d[tmp[1]] || d[lca(c, D)] > d[tmp[1]])) {
f = 1;
ans = 0;
}
a = tmp[1], b = tmp[2];
}
if (!f)// cout << "GG";
ans = d[a] + d[b] - 2 * d[lca(a,b)] + 1;
cout << ans << endl;
}
}
return 0;
}
J-VAT MAN
签到