菜狗自救(3.29&4.5&4.12&4.19)

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];
用途:
差分数组可以快速处理区间加减操作和前缀和。

  1. 处理加减操作时,假设[L,R]上的每一个数组元素+=k,则只需要在前缀数组f[L]处+=k,在f[R+1]-=k,就可,
  2. 前缀和操作如上。

先熟悉一下
洛谷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;
}

以及 求一个数字二进制表示中0 和 1的个数
菜狗自救(3.29&4.5&4.12&4.19)_第1张图片

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
签到

你可能感兴趣的:(ACM-乱七八糟)