天梯赛刷题小记 —— L2

最近在重刷 天梯赛,浅浅记录一下,进入L2阶段了


L2-001 紧急救援

解题思路:典型的dijkstra模板题,带路径记录与权重,方案数记录,解析出过     Dijkstra(兼路径)

#include <bits/stdc++.h>
#define inf 0x3f3f3f
using namespace std;
const int N = 510;
int n, m, s, d;
int mp[N][N];
int dis[N], path[N], num[N], cot[N], sum[N];
bool st[N];
//先找到最短路径,再用相等条件下的最优解,记录最优解路径
//输出最短路径数量,输出最优解能召集到的最多数量的救援队,输出最优解路径

void dijkstra(){
    memset(dis, inf, sizeof(dis));
    memset(cot, 0, sizeof(cot));
    memset(st, false, sizeof(st));
    memset(sum, 0, sizeof(sum));
    sum[s] = num[s];
    cot[s] = 1;
    dis[s] = 0;
    for(int i =0; i<n; i++){
        int t = -1;
        for(int j=0; j<n; j++)
            if(!st[j] && ( t == -1 || dis[t] > dis[j])) t = j;
         st[t] = true;
        //cout<<t<<endl;
         for(int j = 0; j<n; j++){
             if(dis[j] > dis[t] + mp[t][j]){
                 path[j] = t;
                 dis[j] = dis[t] + mp[t][j];
                 cot[j] = cot[t];
                 sum[j] = sum[t] + num[j];
             }else if(dis[j] == dis[t] + mp[t][j]){
                 cot[j] += cot[t];
                 if(sum[j] < sum[t]+num[j]){
                     sum[j] = sum[t]+num[j];
                     path[j] = t;
                 }
             }
         }
    }
}
void printPath(int x, int y){
     if(y == x) cout<<x;
     else {
         printPath(x, path[y]);
         cout<<' '<<y;
     }
}
int main()
{
    cin>>n>>m>>s>>d;
    memset(mp, inf, sizeof(mp));
    memset(num, 0, sizeof(num));
    int x, y,z; 
    for(int i = 0; i< n; i++) cin>>num[i];
    while(m--){
        cin>>x>>y>>z;
        mp[y][x] = mp[x][y] = min(mp[x][y], z);
    }
    dijkstra();
    cout<<cot[d]<<' '<<sum[d]<<endl;
    printPath(s, d);
    return 0;
}

L2-002 链表去重

解题思路:指针,先读入,再两个分别用两个指针指向两个序列,记录序列头,重复情况用st记录键值最大也就1e4

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
bool st[N];
int  e[N], ne[N];
int main()
{
    int fpos, anspos1=-1, anspos2 = -1, spos = -1, tpos = -1,n;
    cin>>fpos>>n;
    int a, b, c;
    for(int i = 0; i<n ;i++){
        cin>>a>>b>>c;
        e[a] = b; ne[a] = c;
    }
    memset(st, false, sizeof(st));
    while(fpos != -1){
        if(st[abs(e[fpos])] == false ) {
            if(anspos1 == -1) anspos1 = fpos, anspos2= fpos;
            else ne[anspos2] = fpos, anspos2 = fpos; 
           st[abs(e[fpos])] = true;
        }else{
            if(spos == -1) spos = fpos, tpos = fpos;
            else ne[tpos] = fpos , tpos = fpos;
        }
        fpos = ne[fpos];
    }
    ne[tpos] = -1;
    ne[anspos2] = -1;
    while(anspos1 != -1){
        printf("%05d %d ", anspos1, e[anspos1]);
        if(ne[anspos1] != -1) printf("%05d\n", ne[anspos1]);
        else cout<<-1<<endl;
        anspos1 = ne[anspos1];
    }
    while(spos != -1){
        printf("%05d %d ", spos, e[spos]);
        if(ne[spos] != -1) printf("%05d\n", ne[spos]);
        else cout<<-1<<endl;
        spos = ne[spos];
    }
    return 0;
}

L2-003 月饼

解题思路:自定义排序,测试点2是 库存或者价格可能为小数

L2-004 这是二叉搜索树吗?

解题思路:树的遍历与遍历序列切割,经典,找符合条件的左右孩子,重塑树,同时考虑单调的特殊情况。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e3+10;

vector<int > ans, ans2, p(1010);
void build1(int l, int r){
    if(l > r) return ; 
    int x = l+1, y = r;
    while(x <= r && p[x] < p[l]) x++;
    while(y > l && p[y] >= p[l]) y--;
    if(x - y != 1 ) return ;
    build1(l+1, y);
    build1(x, r);
     ans2.push_back(p[l]);
}
void build2(int l, int r){//镜像
    if(l > r) return ;
    int x = l+1, y = r;
    while(x <= r && p[x] >= p[l]) x++;
    while(y > l && p[y] < p[l]) y--;
    
    if(x - y  != 1 ) return ;
    build2(l+1, y);
    build2(x, r);
    ans2.push_back(p[l]);
}
signed main()
{
    int n;
    cin>>n;
    for(int i = 1; i<=n; i++){
         cin>>p[i];
    }
    build1(1, n);
    bool flag = false;
    if(ans2.size() == n){
        cout<<"YES"<<endl;
        for(int i = 0; i< ans2.size(); i++)
            if(i == 0) cout<<ans2[0];
            else cout<<' '<<ans2[i];
    }else{
        ans2.clear();
        build2(1, n);
        if(ans2.size() == n){
            cout<<"YES"<<endl;
            for(int i = 0; i< ans2.size(); i++)
            if(i == 0) cout<<ans2[0];
            else cout<<' '<<ans2[i];
        }
        else {
            cout<<"NO";
        }
    }
    cout<<endl;
	return 0;
}

L2-005 集合相似度

解题思路:STL yyds, 用set, find

L2-006 树的遍历

解题思路:思考过程如下,经典的知道其中两个遍历序列,求另一种,这里是求了层序遍历复杂点,求先序简单。

#include <bits/stdc++.h>
using namespace std;
const int N = 500;
struct node{
    int x, l, r;
}tree[N];
int last[N], mid[N];
int idx = 0;
vector<int > ans ;
int rebuild(int l1, int r1, int l2, int r2){
    int pos;
    if(l1 > r1) return -1;
    for(int i = l1; i<= r1; i++)
        if(mid[i] == last[r2]){
            pos = i; break;
        }
    idx++;
    int ret = idx;
    tree[ret].x = last[r2];
    tree[ret].l = rebuild( l1, pos-1, l2, l2+pos-1-l1);
    tree[ret].r = rebuild( pos+1, r1, l2+pos-l1, r2-1);
    return ret;
}
void bfs(){
    queue<int> q;
    q.push(1);
    ans.clear();
    while(q.size()){
        int tmp = q.front();
        q.pop();
        if(tree[tmp].l != -1) q.push(tree[tmp].l);
        if(tree[tmp].r != -1) q.push(tree[tmp].r);
        ans.push_back(tree[tmp].x);
    }
}
int main()
{
   int n;
    cin>>n;
    for(int i = 1; i<=n; i++)  cin>>last[i];
    for(int i = 1; i<=n; i++)  cin>>mid[i];
    int pos = rebuild( 1, n, 1, n);
    bfs();
    cout<<ans[0];
    for(int i=1; i<ans.size(); i++)
        cout<<' '<<ans[i];
    cout<<endl;
    return 0;
}

L2-007 家庭房产

解题思路:结构体,自定义比较函数,并查集,格式化输出,状态计数

首先读入,对所有存在的人计数,人的编号都4位,同时合并集合,使用临时容器,开始合并同集合的人数与房产,重新标记不重复找出所有的答案,再对答案进行排序输出。

AC代码:

#include <bits/stdc++.h>
#define ll long long 
#define rep(x, a, b) for(int x = a; x <= b; x++)
#define pre(x, a, b) for(int x = b; x >= a; x--)
using namespace std;
const int N = 1e4+10;
//家庭信息首先按人均面积降序输出,若有并列,则按成员编号的升序输出。
//并查集!,合并同一家人的信息,先合并,合并人数和房产信息,合并到家庭成员的最小编号的身上,边读边合并吗?
bool st[N], st2[N];
int f[N];
struct node{
    int id, cotm, sumh;
    ll sum;
}nd[N], ans[N], tmp[N];
bool cmp(node a, node b){
    if(a.sum*1.0* b.cotm != b.sum*1.0 * a.cotm) return a.sum*1.0* b.cotm > b.sum*1.0 * a.cotm;
    return a.id<b.id;
}
int find(int x){
    if(x == f[x]) return x;
    else find(f[x]);
}
void merge(int a, int b){
    int x = find(a), y = find(b);
    if(x > y) f[x] = y; 
    else f[y] = x;
}

int main()
{
   int n;
    int a, b ,c, d, tmpcot, tmparea;
    cin>>n;
    memset(st2, false, sizeof(st));
    memset(st, false, sizeof(st));
    for(int i = 0; i< N; i++) f[i] = i; //并查集初始化
    for(int i = 0; i< n; i++){
        cin>>a>>b>>c>>d;
        st[a] = true;
        if(b != -1) merge(a, b), st[b] = true;
        if(c != -1) merge(a, c) , st[c] = true;
        for(int j = 0; j< d; j++){
            cin>>b;
            if(b != -1) merge(b, a),st[b] = true;
        }
        cin>>tmpcot>>tmparea;
        nd[i].id = a;nd[i].cotm = d; nd[i].sumh = tmpcot; nd[i].sum = tmparea;
    }
    for(int i = 0; i<N; i++){
        int t = find(nd[i].id);
        tmp[t].sumh += nd[i].sumh;
        tmp[t].sum += nd[i].sum;
        if(st[i]) tmp[find(i)].cotm++;
    }
    int idx = 0;
    for(int i = 0; i<N; i++){
        int x = find(i);
        if(st[x] && !st2[x]){
            ans[idx].id = x;
            ans[idx].cotm = tmp[x].cotm;
            ans[idx].sumh = tmp[x].sumh;
            ans[idx].sum  = tmp[x].sum;
            idx++;
            st2[x] = true;
        }
    }
    sort(ans, ans+idx, cmp);
    cout<<idx<<endl;
    for(int i = 0; i< idx; i++){
        printf("%04d %d %.3lf %.3lf\n", ans[i].id, ans[i].cotm, (double)(ans[i].sumh*1.0/ans[i].cotm), ans[i].sum*1.0/ans[i].cotm);
    }
    return 0;
}

L2-008 最长对称子串

解题思路:字符串,指针

L2-009 抢红包

解题思路:自定义排序,结构体

L2-010 排座位

解题思路:数量级比较小,关系用二维矩阵记录,朋友的朋友,与敌人之间的共同朋友用并查集解决,再做个判断。

L2-011 玩转二叉树

解题思路:与L2-006 树的遍历差不多,样例树都长得一样6

L2-012 关于堆的判断

解题思路:考察了堆的特质,注意点是读入,读完之后要把整行都吸收了,不然会影响后面的判断。make_heap(a.begin(),a.end(),greater<int>());, 用容器也可以,自己简单的堆排序也可以

L2-013 红色警报
//思路:首先是否分裂国家,就看去掉这个城市后后,有没有导致出新的集合,需要记录去掉该城市前后的集合数量
//若去掉城市后集合数量为0 ,则game over,进行条件判断
//如何获取集合数量,解决连通性问题,使用并查集,然后遍历所有城市获取父节点,再用set去重
// 时空限制:城市数500 ,M 5000, k最大也就500, 5000*500 = 2e6左右,不会爆

#include <bits/stdc++.h>
#define int long long
#define inf 0x3f3f3f
#define ft first
#define sd second
#define PII pair<int, int>
using namespace std;

const int N = 1e4+10;
PII g[N];
bool lost[N];
set<int> st;
int f[N];
int find(int x){
    if(x == f[x]) return x;
    return f[x] = find(f[x]);
}
void merge(int a, int b){
    f[find(a)] = find(b);
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int n, m;
    int pre = 0, cur = 0;
    cin>>n>>m;
    for(int i = 0; i< n; i++) f[i] = i;
    for(int i = 0; i< m; i++){
        cin>>g[i].ft>>g[i].sd;
        merge(g[i].ft, g[i].sd);
    }
    memset(lost, false, sizeof(lost));
    st.clear();
     for(int i = 0; i<n; i++) st.insert(find(i));
    pre = st.size();
    int k, x;
    cin>>k;
    while(k--){
        cin>>x;
        st.clear();
        lost[x] = true;
        for(int i = 0; i<n; i++) f[i] = i;
        for(int i = 0; i<m; i++)
            if(!lost[g[i].ft] && !lost[g[i].sd])
                merge(g[i].ft, g[i].sd);
        for(int i = 0; i<n; i++)
            if(!lost[i])st.insert(find(i));
        cur = st.size();
//         cout<<pre<<' '<<cur<<endl;
        if(cur <= pre) cout<<"City "<<x<<" is lost."<<endl;
        else if(cur > pre) cout<<"Red Alert: City "<<x<<" is lost!"<<endl;
        if(cur == 0) cout<<"Game Over."<<endl;
        pre = cur;
    }
    return 0;
}

L2-014 列车调度

解题思路:

思考如下:

 每次只记录队尾,用更小的数字代替较大的队尾,因为在序列内部也是递减的,所以使用lower_bound函数寻找第一个大于等于x的值并删除它,代替它,测试点三,错在不能用vector,和lower_bound函数一起用,因为vector有序,而插入的数字每次都是直接push_back在尾部,而lower_bound是遇到一个符合条件的就结束了,不能找到最小的符合条件的,如果每次都调用sort会超时,此时应该使用set, 然后新的错误又出现了,测试点1和测试点3一起超时了!!!:(

然后查了一下资料,我在对set使用lower_bound(st.begin(), st.end(), x)就像vector一样,导致了超时,set本身无序,使用st.lower_bound(x),更快。

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define PII pair<int, int>
#define rep(x, a, b) for(int x = a; x<=b; x++)
#define pre(x, a, b) for(int x = b; x>=a; x--)
using namespace std;
const int N = 1e5+10;
set<int> vt;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int n, x;
    cin>>n;
    vt.clear();
    set<int>::iterator  it;
    for(int i = 0; i< n; i++){
        cin>>x;
        it = vt.lower_bound( x);
        if(it != vt.end()) {
            vt.erase(it);
            vt.insert(x);
        }else vt.insert(x);
    }
    cout<<vt.size()<<endl;
	return 0;
}

L2-015 互评成绩

解题思路:排序

#include <bits/stdc++.h>
#define inf 0x3f3f3f
using namespace std;
const int N = 1e4+10;
double a[N];
int main(){
    int n, k, m, x, minx, maxx;
    int sum = 0;
    cin>>n>>k>>m;
    for(int i = 0; i<n; i++){
        sum = 0;
        minx = inf, maxx = 0;
        for(int j = 0; j< k; j++){
            cin>>x;
            sum += x; minx= min(minx, x); maxx=max(x, maxx);
        }
        sum -= minx; sum -= maxx;
        a[i] = 1.0*sum / (k-2);
    }
    sort(a, a+n);
    for(int i=m-1; i>=0; i--){
        if(i != 0) printf("%.3lf ", a[n-1 -i]);
        else printf("%.3lf\n", a[n-1 -i]);
    }
    return 0;
}

L2-016 愿天下有情人都是失散多年的兄妹

解题思路:这道题不难但是 我卡在了第0个点我就是一个sb... 主要是 我把父母的性别标记反了栓Q,dfs,遍历标记五代,然后第二遍标记 如果遇到已经被标记的就是不能在一起的有情人。还有要初始化不然祖宗全是0,然后全都不能在一起了,还有st, 与其dfs搞返回值判断情况,还不如设定一个全局变量会更好用。

#include <bits/stdc++.h>
#define inf 0x3f3f3f
using namespace std;
const int N =1e6+10;
//向上五个代并标记,如果第二个人向上五代遇到了标记则,不行,若没有则可以
bool st[N];
struct node{
    int  f, m;
    char sex;
}p[N];
bool flag;
void dfs(int x, int d){
   if(d == 5 || x == -1)return ;
    if(st[x] || flag){
         flag = true;
        return ;
    }
    st[x] = true;
    if(p[x].f != -1) dfs(p[x].f, d+1);
    if(p[x].m != -1) dfs(p[x].m, d+1);
}
int main()
{
    int n, x;
    cin>>n;
    for(int i = 0; i<N; i++)
        p[i].f = p[i].m = -1;
    for(int i = 0 ;i< n; i++){
        cin>>x>>p[x].sex>> p[x].f >> p[x].m ;
        if(p[x].f != -1) p[p[x].f].sex = 'M';
         if(p[x].m != -1) p[p[x].m].sex = 'F';
    }
    int k, a, b;
    cin>>k;
    while(k--){
        cin>>a>>b;
        if(p[a].sex == p[b].sex) cout<<"Never Mind"<<endl;
        else {
            flag = false;
            memset(st,false, sizeof(st));
            dfs(a, 0);
            dfs(b, 0);
            if(flag) cout<<"No"<<endl;
            else cout<<"Yes"<<endl;
        }
    }
    return 0;
}

L2-017 人以群分

解题思路:排序,条件

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define int long long
#define PII pair<int, double>
#define rep(x, a, b) for(int x = a; x<=b; x++)
#define pre(x, a, b) for(int x = b; x>= a; x--)

using namespace std;
const int N = 2e5+10;
double k[N];
double a[N], b[N];
vector< PII > ans1, ans2;
signed main()
{

 	int n, m, max_aidx = -inf,max_bidx = -inf, max_ = 0;
    memset(a, 0, sizeof(a));
    memset(b, 0, sizeof(b));
    memset(k, 0, sizeof(k));
 	cin>>n;
	rep(i, 1, n)
	{
		int x;
		cin>>x>>a[x];
		max_aidx = max(max_aidx, x);
	}
	cin>>m;
	rep(i, 1, m)
	{
		int x; 
		cin>>x>>b[x];
  		max_bidx = max(max_bidx, x);
    }
    //cout<<max_aidx<<' '<<max_bidx<<endl;
   max_ = max_aidx -max_bidx;
	while(max_bidx <= max_aidx)
	{
		
		int x = max_aidx - max_bidx;
		double y = a[max_aidx] / b[max_bidx];
		k[x] = y;
		for(int i = max_aidx, j = max_bidx; i>= 0 && j>= 0; i--, j--)
			{
				a[i] -= b[j]*y;
			}
		while(a[max_aidx] == 0) max_aidx--;
	}
    pre(i, 0, max_){ //从 商的最大指数开始枚举,不然会错。
        if(abs(k[i]) + 0.05 >= 0.1){
            ans1.push_back(make_pair(i, k[i]));
        }
    }
     pre(i, 0, max_aidx){
        if(abs(a[i]) + 0.05 >= 0.1){
           ans2.push_back(make_pair(i, a[i]));
        }
    }
    if(ans1.size() == 0)
    {
        cout<<"0 0 0.0"<<endl;
    }
    else {
        cout<<ans1.size();
        rep(i, 0, ans1.size() - 1) printf(" %lld %.1lf", ans1[i].first, ans1[i].second);
        cout<<endl;
    }
    if(ans2.size() == 0) {
        cout<<"0 0 0.0"<<endl;
    }else{
        cout<<ans2.size();
        rep(i, 0, ans2.size() - 1) printf(" %lld %.1lf", ans2[i].first, ans2[i].second);
        cout<<endl;
    }
	return 0;
}

L2-019 悄悄关注

解题思路:排序,状态映射,简单判断

L2-020 功夫传人

解题思路:模拟题,bfs, 注意点在于 祖师爷本人可能是得道者,这个点好像是测试点(1还是2还是3来着忘了,特判一下)

#include <bits/stdc++.h>
#define ft first
#define sd second
using namespace std;
const int N = 1e5+10;
int n;
double z, r;
int t[N];
int st[N];
vector<int> v[N];
double sum[N];
int main()
{
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    cin>>n>>z>>r;
   for(int i = 0; i< n; i++)
       st[i] = 1;
    int k, id;
    for(int i = 0; i< n; i++){
        cin>>k;
        if(!k){
           cin>>st[i];
        }
        else{
            for(int j  = 0; j< k; j++)
            {
                cin>>id;
                v[i].push_back(id);
            }
        }
    }
    
    double x = 1 - r * 0.01;
    double ans = 0;
    queue< pair<int, double> > q;
    q.push(make_pair(0, z*st[0]));
    if(st[0] != 1 )ans += ( z*st[0]);
    
    while(q.size()){
        pair<int, double> teacher = q.front(); q.pop();
        double tmp = x * teacher.sd;
      for(int i = 0; i< v[teacher.ft].size(); i++){
           if(st[v[teacher.ft][i]] != 1){
                 ans += (tmp * st[v[teacher.ft][i]]);
              }
             q.push(make_pair(v[teacher.ft][i], tmp * st[v[teacher.ft][i]] ));
        }
        
    }
    printf("%d\n", (int)ans);
    return 0;
}

L2-021 点赞狂魔

解题思路:没啥特别,自定义结构体排序,格式化输出

#include <bits/stdc++.h>
#define ft first
#define sd second
#define PII pair<int, string>
using namespace std;
const int N = 1e5+10;
struct node {
    string name;
    int cnt, cotb;
}p[N];
set<int> blog;
bool cmp(node a, node b){
    if(a.cotb != b.cotb) return a.cotb > b.cotb;
    return (1.0*a.cnt/a.cotb) < (1.0*b.cnt/b.cotb);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int n;
    cin>>n;
    int k;
    for(int i = 0; i< n; i++){
        blog.clear();
        cin>>p[i].name>>p[i].cnt;
        for(int j = 0; j<p[i].cnt; j++){
            cin>>k;
            blog.insert(k);
        }
        p[i].cotb = blog.size();
    }
    sort(p, p+n, cmp);
    vector<string> ans;
    for(int i = 0; i< n; i++){
        if(i<3)ans.push_back(p[i].name);
        else break;
        //cout<<p[i].name<<' '<<p[i].cnt<<' '<<p[i].cotb<<endl;
    }
    while(ans.size() < 3) ans.push_back("-");
    cout<<ans[0]<<' '<<ans[1]<<' '<<ans[2];
    return 0;
}

L2-022 重排链表

解题思路:模拟题,测试点2在于最小规模N= 2时的特判

可恶,上次编辑的内容没保存,懒得写了,这个版本的思路就是,记录前驱和后继,然后双指针遍历,记录是否遍历过,遇到 遍历过的就跳出,输出没被遍历的最后一个点,注意输出格式

还有一个去年写的版本也不错!,但是懒得找了

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
struct node{
    int data, next, pre;
}p[N];
bool st[N];
int bpos,epos;

int main(){
    int n;
    cin>>bpos>>n;
    memset(st, false, sizeof(st));
    int x, y,z;
    p[bpos].pre = -1;
    for(int i = 0; i< n; i++){
        cin>>x>>p[x].data>>p[x].next;
        p[p[x].next].pre = x;
        if(p[x].next == -1) epos = x;
    }
     if(!st[epos]){
         printf("%05d %d ", epos, p[epos].data);
         if(!st[p[epos].pre])  st[epos] = true,epos = p[epos].pre;
         if(n==2){
             printf("%05d\n%05d %d -1", epos, epos, p[epos].data);
             return 0;
         }
     }
     while(!st[epos] && !st[bpos]){
          if(!st[bpos]) printf("%05d\n%05d %d ", bpos, bpos, p[bpos].data);
         st[bpos] = true;
          bpos = p[bpos].next;
         if(epos == -1 || bpos == -1 ) break;
          if(!st[epos]) printf("%05d\n%05d %d ", epos, epos, p[epos].data);
        st[epos] = true;
         epos = p[epos].pre;
         if(epos == -1 || bpos == -1 ) break;
     }
    if(!st[epos])  printf("%05d\n%05d %d ", epos, epos, p[epos].data);
    else if(!st[bpos])  printf("%05d\n%05d %d ", bpos, bpos, p[bpos].data);
    cout<<-1<<endl;
    return 0;
}

L2-023 图着色问题

解题思路:模拟题,数据量小,没有坑点

#include <bits/stdc++.h>
using namespace std;
const int N = 550;
int mp[N][N];
int vt[N];
set<int> st;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int v, e, k, x, y;
    cin>>v>>e>>k;
    memset(mp, 0, sizeof(mp));
    for(int i = 0; i<e; i++){
        cin>>x>>y;
        mp[x][y] = mp[y][x] = 1;
    }
    int n;
    cin>>n;
    while(n--){
        st.clear();
        for(int i = 1; i<= v; i++){
            cin>>x; vt[i] = x;
            st.insert(x);
        }
        if((int)st.size() !=  k){
            cout<<"No"<<endl;
            continue;
        }
        bool flag = false;
        for(int i = 1; i<=v && !flag; i++){
            for(int j = 1; j<=v && !flag; j++){
                if(i == j || !mp[i][j]) continue;
                if(vt[i] == vt[j]) 
                    flag = true;
            }
        }
        if(!flag) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
}

L2-024 部落

解题思路:带状态映射的并查集

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int p[N], f[N];
bool vis[N];
set<int> st;
int find(int x)
{
    if(x == f[x]) return x;
    return f[x] = find(f[x]);
}
void merge(int a, int b)
{
    int x = find(a), y = find(b);
    p[x] += p[y];
    f[y] = x;
}
int main(){
    int n;
    cin>>n;
    memset(vis, false, sizeof(vis));
    st.clear();
    for(int i = 0; i< N; i++) f[i] = i, p[i] = 1;
    for(int i = 0; i< n; i++){
        int k,x, y;
        cin>>k;
        if(k >= 1) {
            cin>>x; st.insert(x);
        }
        for(int i = 2; i<= k; i++){
            cin>>y;
            merge(x, y);
            st.insert(y);
        }
    }
    int allb = 0;
    for(auto x: st){
        if(!vis[find(x)]) allb++, vis[find(x)] = true;
    }
    cout<<st.size()<<' '<<allb<<endl;
    int q, x , y;
    cin>>q;
    while(q -- ){
        cin>>x>>y;
        if(find(x) == find(y)) cout<<"Y"<<endl;
        else cout<<"N"<<endl;
    }
    
    return 0;
}

L2-025 分而治之

解题思路:注意数据的存储方式,虽然是无向图但是每条边都要遍历,所以压的时候只压一次就可以了。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
vector<int> g[N];
bool st[N];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    
    int n, m, x, y;
    cin>>n>>m;
    for(int i = 0; i< m; i++){
        cin>>x>>y;
        g[x].push_back(y);
    }
    
    int k;
    cin>>k;
    while(k--){
        int np, x;
        cin>>np;
        memset(st, false, sizeof(st));
        for(int i = 0; i< np; i++){
            cin>>x;
            st[x] = true;
        }
        bool flag = false;
        for(int i = 0; i< n&&!flag; i++){
            if(!st[i]){
                for(int j = 0; j< g[i].size() && !flag; j++){
                    if(!st[g[i][j]]){
                        flag = true; break;
                    }
                }
            }
        }
        if(flag) cout<<"NO"<<endl;
        else cout<<"YES"<<endl;
    }
    return 0;
}

L2-026 小字辈

解题思路:反向记录孩子, 然后构建一颗树,使用bfs广度优先遍历,记录深度,同时记录每个编号的对应深度,最后输出最深的,再用深度输出一样大的的元素;

#include <bits/stdc++.h>
#define PII pair<int , int>
using namespace std;
const int N = 1e5+10;
vector<int> son[N], ans;
int b[N];
int main(){
    int n, x;
    cin>>n;
    int f = 0;
    for(int i = 1; i<=n; i++){
        cin>>x;
        if(x!=-1) son[x].push_back(i);
        else f = i;
    }
    queue< PII> q;
    q.push(make_pair(f, 1));
    memset(b, 0, sizeof(b));
    int max_one = 0;
    while(q.size()){
        PII tmp = q.front(); q.pop();
        b[tmp.first] = tmp.second;
        max_one = max(max_one, tmp.second);
        for(int i = 0; i< son[tmp.first].size(); i++)
            q.push(make_pair(son[tmp.first][i], tmp.second+1));
    }
    for(int i = 1; i<=n; i++)
        if(max_one == b[i]) 
            ans.push_back(i);
    cout<<max_one<<endl;
    for(int i = 0; i< ans.size(); i++){
        if(i == 0) cout<<ans[i];
        else cout<<' '<<ans[i];
    }
    return 0;
}

L2-027 名人堂与代金券

解题思路:pair, 自定义排序,注意输出,测试点4在于k>n的情况。输出时要注意min(k, n);

#include <bits/stdc++.h>
#define ft first
#define sd second
#define PII pair<int, string> 
#define int long long
using namespace std;
const int N = 1e4+10;
PII p[N];
bool cmp(PII a, PII b){
    if(a.ft != b.ft) return a.ft > b.ft;
    return a.sd < b.sd;
}
signed main(){
    int n, g, k;
    cin>>n>>g>>k;
    for(int i = 0; i < n; i++){
        cin>>p[i].sd>>p[i].ft;
    }
    sort(p, p+n, cmp);
    int ans = 0;
    for(int i = 0; i< n; i++)
    {
        if(p[i].ft >= g && p[i].ft <= 100 ) ans+= 50;
        else if(p[i].ft >= 60 && p[i].ft < g) ans += 20;
        else break;
    }
    cout<<ans<<endl;
    for(int i = 0, idx = 1; i<n && idx<=min(k, n); i++){
        if(!i) cout<<1;
        else{
            if(p[i-1].ft == p[i].ft) cout<<idx;
            else {
                idx = i+1;
                if(idx <= k) cout<<idx;
            }
        }
       if(idx <= k) cout<<' '<<p[i].sd<<' '<<p[i].ft<<endl;
    }

    return 0;
}

L2-028 秀恩爱分得快

解题思路:刚开始 测试点3,6过不了,后来看了帖子,才知道 读入点为-0的问题!!!,我还奇怪我之前为啥这题的读入用的是string ,阿西,还有一个问题就是超时,1e3 * 500 = 5e5不会爆但是数据处理要高明一点, 还有就是检查一下照片中有没有这两个人,如果没有就可以不考虑这张照片无用。

#include <bits/stdc++.h>
#define int long long
#define PII pair<bool, int>
using namespace std;
const int N = 1e3+10;
bool is[N];
vector<int> v[N];

double aa[N], bb[N];
int tun(string s)
{
	int rt = 0;
	for(int i = 0; i<(int)s.length(); i++)
		if(s[i] >= '0' && s[i] <= '9')
			rt = rt*10 + (int)(s[i] - '0');
	return rt;
}
signed main(){
    memset(is, false, sizeof(is));
    int n, m;
    cin>>n>>m;
    for(int i = 0; i<m; i++){
        int k, x;
        cin>>k;
        for(int j =0 ;j < k; j++){
            string x;
            cin>>x;
            int tmp = tun(x);
            if(x[0] =='-') is[tmp] = true;
            v[i].push_back(tmp);
        }
    }
    string aaa, bbb;
    int a, b;
    cin>>aaa>>bbb;
    a = tun(aaa), b = tun(bbb);
    if(aaa[0] == '-')is[a] = true;
    if(bbb[0] == '-') is[b] = true;
    double maxa = 0, maxb = 0;
    for(int i = 0; i< m; i++){
        bool flaga = false, flagb = false;
        for(int j = 0; j< v[i].size(); j++){
            if(v[i][j] == a) flaga = true;
            if(v[i][j] == b) flagb = true;
        }
        if(flaga || flagb){
            double score = 1.0/v[i].size();
            for(int j = 0; j<v[i].size(); j++){
                if(flaga && is[a] != is[v[i][j]]) 
                    aa[v[i][j]] += score, maxa = max(maxa, aa[v[i][j]]);
                if(flagb && is[b] != is[v[i][j]]) 
                    bb[v[i][j]] += score, maxb = max(maxb, bb[v[i][j]]);
                
            }
        }
    }   
    if(maxa == aa[b] && maxb == bb[a])  cout<<aaa<<' '<<bbb<<endl;
    else{
        for(int i = 0; i< n; i++){
            if(is[i] != is[a] && maxa == aa[i])
            {
                cout<<aaa<<' ';
                if(is[i]) cout<<'-'<<i<<endl;
                else cout<<i<<endl;
            }
        }
        for(int i = 0; i< n; i++){
            if(is[i]!=is[b] && maxb == bb[i])
            {
                 cout<<bbb<<' ';
                if(is[i]) cout<<'-'<<i<<endl;
                else cout<<i<<endl;
            }  
        }
    }
    return 0;
}

结论:做人和做事一样要细心,认真,善良,耐心一点

L2-029 特立独行的幸福

解题思路:数学题,分步骤处理,判断素数与获取其各位数平方和函数,在判断是否为幸福数时,使用状态进行记录,排除一些过程中产生的幸福数,每次判断幸福数的时候都要从新初始化一个状态数组遇到循环就跳出。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e4+10;
bool a[N];
int b[N];
bool isp(int x){
    for(int i = 2; i*i <= x; i++)
        if(x % i == 0) return false;
    return true;
}
int get(int x){
    int ret = 0;
    while(x){
        ret = ret + (x%10) * (x%10);
        x /= 10;
    }
    return ret;
}
bool ishappy(int x){
    bool st[N];
    memset(st,false, sizeof(st));
    int t = x;
    int cnt = 0; 
    bool flag = false;
    vector<int> tmp;
    while(true){
        int ttp = get(x);
        if(ttp == 1){
            tmp.push_back(ttp);
            cnt++;
            flag = true;
            break;
        }
        else{
            if(!st[ttp]){
                 st[ttp] = true, tmp.push_back(ttp),cnt++;
            }
            else break;
        }
        x = ttp;
    }
    if(flag){
        for(int i = 0; i< tmp.size(); i++)
            a[tmp[i]] = true;
        b[t] = cnt; 
    }
    return flag;
}
int main()
{
    vector<int> ans;
    int n, m;
    cin>>n>>m;
    memset(a, false, sizeof(a));
    for(int i = n; i<= m; i++){
        if(ishappy(i))
            ans.push_back(i);
    }
   
  if(ans.size()){
        for(int i = 0; i<ans.size(); i++){
        if(!a[ans[i]]){
            cout<<ans[i]<<' ';
            if(isp(ans[i])) cout<<b[ans[i]]*2<<endl;
            else cout<<b[ans[i]]<<endl;
        }
    }
  }
    else cout<<"SAD"<<endl;
    return 0;
}

L2-030 冰岛人

解题思路:这个坑暂时不填了,等打完再说,这道题过19分,差不多了

我的测试点3,4,6没过,看了一下别人的贴子好像出现在

所谓“五代以内无公共祖先”是指两人的公共祖先(如果存在的话)必须比任何一方的曾祖父辈分高。(测试点3, 6)

就是用单纯的dfs标记无法检测到,一种情况,存在 共同祖先,但由于其中一方辈分较低,只标记了三层,没有检测到重复标记则此时,认为两个人可以勾搭到一起(实际上不行!!!),需改进!

#include <bits/stdc++.h>
using namespace std;
const int N =1e5+10;
map<string, bool> st;
map<string, int> stt;
map<string, string> f;
bool dfs(string x, int d){
    if(d == 3)  return false;
    if(f.find(x) == f.end() ) return false;
    string y = f[x];
    if(stt[y]) return true;
    stt[y] = true;
    return dfs(y, d+1);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int n, m;
    string a, b, c, d;
     cin>>n;
    for(int i = 0; i<n; i++){
        cin>>a>>b;
        int len = b.length();
        string tmp;
        if((len - 4 >= 0) && b.substr(len-4, 4)  == "sson") 
            st[a] = true, tmp = b.substr(0, len-4);
        else if((len-7 >= 0) && b.substr(len-7, 7) == "sdottir") 
            st[a] = false, tmp = b.substr(0, len - 7);
        else {
            if(b[len-1] == 'f') st[a] = false;
            else st[a] = true;
            tmp =b.substr(0, len-1);
        }
        st[tmp] = true;
        f[a] = tmp;
    }
    
    cin>>m;
    while(m -- ){
        cin>>a>>b>>c>>d;
        if(st.find(a) == st.end() || st.find(c) == st.end()) cout<<"NA"<<endl;
        else if(st[a] == st[c]) cout<<"Whatever"<<endl;
        else if(st[a] != st[c]){
            for(auto x: f)
                stt[x.first] = false;
            bool flag = dfs(a, 0);
            flag = dfs(c, 0);
            if(flag) cout<<"No"<<endl;
            else cout<<"Yes"<<endl;
        }
    }
    return 0;
}

 L2-031 深入虎穴

解题思路:这次用的是 dfs,去年写的是bfs, 然后今年测试点一错了,maxd 要取-1, 出口也是最深的门。

AC代码(dfs):
 

#include <bits/stdc++.h>
#define ft first 
#define sd second
#define PII pair<int, int> 
using namespace std;
const int N = 1e5+10;
//1.找入口,使用st 标记
// 树 ,dfs, 深度记录
//数据量, 使用邻接表记录
vector<int> door[N];
bool st[N];
int ans = 0, maxd = -1;
void dfs(int x, int d){
    if(!door[x].size()){
        if(maxd < d) {
            ans = x;
            maxd = d;
        }
        return ;
    }
    for(int i = 0; i< door[x].size(); i++)
        dfs(door[x][i], d+1);
}
int main()
{
    int n, k, x;
    memset(st, false, sizeof(st));
    cin>>n;
    for(int i = 1; i<= n; i++){
        cin>>k;
        while(k--){
            cin>>x;
            door[i].push_back(x); 
            st[x] = true;
        }
    }
    int pos = 0;
    for(int i = 1; i<N; i++)
        if(!st[i]){
            pos = i;
            break;
        }
    dfs(pos, 0);
    cout<<ans<<endl;
    return 0;
}

AC代码(bfs):

#include <bits/stdc++.h>
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define rep(x, a, b) for(int x = a; x<= b; x++)
#define int long long
using namespace std;
const int N = 1e5+10;
vector<int> g[N];
bool st[N];
int root;
void bfs()
{
	queue<pair<int, int> > q;
	q.push({root, 1});
	int ansd = 0, ans = 0;
	while(q.size())
	{
		pair<int , int>  x = q.front();
		q.pop();
		if(ansd < x.second)
		{
			ansd = x.second;
			ans = x.first;
		}
		for(int i = 0; i< (int)g[x.first].size(); i++)
		{
			q.push({g[x.first][i], x.second+1});
		 } 
	}
	cout<<ans<<endl;
}
signed main()
{
	int n;
	cin>>n;
	rep(i, 1, n)
	{
		int k,x;
		cin>>k;
		rep(j , 1, k){
			cin>>x;
			g[i].push_back(x);
			st[x] = true;
		}
	}
	rep(i , 1, n){
		if(!st[i]) {
			root = i;
			break;
		}
	}
	bfs();
	return 0;
}

L2-032 彩虹瓶

解题思路:限高的堆栈。

#include<bits/stdc++.h>
using namespace std;
const int N =1e5+10;
int main(){
    int n, m, k;
    cin>>n>>m>>k;
    while(k -- ){
        stack<int> st;
        int x, idx = 1;
        bool flag = false;
        for(int i = 0; i< n; i++)
        {
            cin>>x;
            if(!flag){
                if(x == idx){
                    idx++;
                    while(st.size() &&  st.top() == idx){
                        idx++, st.pop();
                    }
                    continue;
                }
                else{
                    st.push(x);
                    if(st.size() > m) flag = true;
                }
            }
        }
        if(flag || idx != n+1) cout<<"NO"<<endl;
        else cout<<"YES"<<endl;
    }
    return 0;
}

L2-033 简单计算器

解题思路:STL

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;

int main()
{
    int n;
    cin>>n;
    int x;
    string tmp;
    stack<int> num;
    stack<char> op;
    for(int i = 0; i< n; i++){
        cin>>x; num.push(x);
    }
    for(int i = 0; i< n - 1; i++){
        cin>>tmp; op.push(tmp[0]);
    }
    bool flag = false;
    int t1, t2;
    while(op.size()){
        t1 = num.top(); num.pop(); 
        t2 = num.top(); num.pop();
        char t = op.top(); op.pop();
        if(t == '/'){
            if(!t1){
                flag = true;
                break;
            }else t2 /= t1;
        }
        else if(t == '+') t2 += t1;
        else if(t == '-') t2 -= t1;
        else if(t == '*') t2 *= t1;
        num.push(t2);
    }
    if(!flag) cout<<num.top()<<endl;
    else cout<<"ERROR: "<<t2<<"/"<<0<<endl;
    return 0;
}

L2-034 口罩发放

解题思路:自定义结构体排序,测试点3还是4来着是对于id中出现非数字的判定

特殊点用map做映射,好处算超出时间可以用i来做时间线!

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int d, p;
struct node{
    string id, name;
    int state;
    int h, m, turn;
    bool operator< (const node& x) const{
        if(x.h != h) return h< x.h;
        if(x.m != m) return m < x.m;
        return turn < x.turn;
    }
};
map<string, int> day,st;
vector<node> v1,v2;
bool check(string x){
    if(x.length() != 18) return false;
    for(int i = 0; i< x.length(); i++)
        if(!isdigit(x[i])) return false;
    return true;
}
int main()
{
    cin>>d>>p;
    for(int i = 0; i< d; i++)
    {
        int t, s;
        cin>>t>>s;
        for(int j = 0; j<t; j++){
            node p;
            cin>>p.name>>p.id>>p.state;
            p.turn = j;
            scanf("%d:%d", &p.h, &p.m);
            if(check(p.id)){
                if(p.state == 1)v1.push_back(p);
                v2.push_back(p);
            }
        }
        sort(v2.begin(), v2.end());
        
        for(int j = 0; j< v2.size() && s; j++)
        {
           if(day.find( v2[j].id ) == day.end() || day[v2[j].id] <= i){
               day[v2[j].id] = i+p+1;
               cout<<v2[j].name<<' '<<v2[j].id<<endl;
               s--;
           }
        }
        v2.clear();
    }
    for(int i = 0; i<v1.size(); i++)
        if(st.find(v1[i].id) == st.end())
        {
            cout<<v1[i].name<<' '<<v1[i].id<<endl;
            st[v1[i].id]++;
        }
    return 0;
}

L2-035 完全二叉树的层序遍历

解题思路:很玄妙,计算如果作为完美二叉树所缺少的点,然后将后序遍历序列进行处理,如果正常就向右子树优先遍历,不断的割最后一位根,就算触及叶子,判断是哪一层的,往右边遍历,如果是属于d1层且缺失节点还没用完,就返回当前的r,继续深入遍历左边的,相当于反向后序遍历解码,然后存储层序遍历序列

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n, d1, d2;
int p[N], p2[N];
int remain = 0;
int getp(int r, int d, int pos){
    if(d == d1 && remain) {
        remain --;
        return r;
    }
    if((!remain && d == d2) || !r)return r; //r == 0 结束
    p2[pos] = p[r];
    int ret = getp(r-1, d+1, pos*2+1); 
    ret = getp(ret, d+1, pos*2);
    return ret;
}
int main(){
    cin>>n;
    for(int i = 1; i<= n; i++) cin>>p[i];
    d1 = log2(n+1);
    d2 = d1;
    if(pow(2, d2) - 1 < n) d2++;
    remain = pow(2, d2) - 1 - n;
    getp(n, 0, 1);
    cout <<p2[1];
    for(int i = 2; i<= n; i++) cout<<' '<<p2[i];
    cout<<endl;
    return 0;
}

L2-036 网红点打卡攻略

解题思路:方案合理性测试问题,模拟,数据量小,选择邻接矩阵,使用set检测是否有重复景点,刚开始的时候测试点4没过,后面把起点0插入路线前后,进行计算cost之后,然后加入了如果超出了inf 或者<0 了就跳出,返回inf,因为我怀疑溢出了, 应该规避了一些特殊情况,然后就过了。这里给出两个版本;

AC代码(2023年):(个人感觉这个版本简单,思路易于理解)

#include <bits/stdc++.h>
#define int long long
#define inf 1e9+1
using namespace std;
const int N = 310;
int g[N][N];
int p[N];
set<int> st;
int getCost(int t){
    int ret  = 0;
    for(int i = 0; i<t+1; i++){
        if(ret > inf || ret < 0) return inf;
        ret += g[p[i]][p[i+1]];
    }
    return ret;
}
signed main(){
    int n, m, k;
   int ans = inf, id = inf;
    int a, b, c;
    cin>>n>>m;
    memset(g, inf ,sizeof(g));
    for(int i = 0; i< m; i++) {
        cin>>a>>b>>c;
        g[b][a] = g[a][b] = c; 
    }
    cin>>k;
    int cot = 0;
    for(int j = 1; j<=k; j++){
        st.clear();
        int t, tmp = 0;
        cin>>t;
        for(int i = 1; i<=t; i++)
        {
            cin>>p[i];
            st.insert(p[i]);
        }
        p[0] = 0; p[t+1] = 0;
        if(st.size() == t && t == n){
           tmp = getCost(t);
            if(tmp < inf && tmp > 0){
                cot++;
                if(tmp < ans) ans = tmp , id = j;
            }
        }
    }
   cout<<cot<<endl<<id<<' '<<ans<<endl;
    return 0;
}

 AC代码(2022):

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define int long long
#define PII pair<int, int>
#define rep(x, a, b) for(int x = a; x<=b; x++)
#define pre(x, a, b) for(int x = b; x>+ a; x--)

using namespace std;
const int N = 1e6+10;
vector<PII >p;
int g[210][210];
bool st[210];
int n, m, w, k;


bool cmp(PII a, PII b)
{
	if(a.first != b.first) return a.first<b.first;
	return a.second < b.second;
}
signed main()
{
	//memset(g, inf, sizeof(g));
	rep(i, 0, 200)
		rep(j, 0, 200)
			g[i][j] = inf;
	ios::sync_with_stdio(false);
	
	cin>>n>>m;
	rep(i, 1, m)
	{
		int x, y;
		cin>>x>>y>>w;
		g[x][y] = w;
		g[y][x] = w;
	}
	
	cin>>k;
	rep(i, 1, k)
	{
		int x, y;
		memset(st, false, sizeof(st)); 
		cin>>x;
		bool flag = false;
		vector<int> temp;
		temp.push_back(0);
		rep(j, 1, x)
		{
			cin>>y;
			temp.push_back(y);
		}
		temp.push_back(0);
		int sum = 0;
		if(x != n) continue;
		rep(j, 1, x+1)
		{
			if(!st[temp[j]]) st[temp[j]] = true;
			else {
				flag = true;
			}
			//cout<<temp[j]<<' '<<temp[j-1]<<endl;
			if(g[temp[j]][temp[j-1]] == inf)
			{
				flag = true;
			}else{
				sum += g[temp[j]][temp[j-1]];
			}
		}
		//cout<<endl<<endl;
		if(!flag && temp.size() == n+2)
		{
			p.push_back(make_pair(sum, i));
		}
		
	}
	
	sort(p.begin(), p.end(), cmp);
	int ans = 0;
	cout<<p.size()<<endl;
	cout<<p[0].second<<' '<<p[0].first<<endl;
	return 0;
}

L2-037 包装机

解题思路:感觉有一个地方具有迷惑性

当筐已经满了,但仍然有某条轨道的按钮被按下时,系统应强制启动 0 号键,先从筐里抓出一件物品,再将对应轨道的物品推落。

此外,如果轨道已经空了,再按对应的按钮不会发生任何事;

但是我认为 后一句优先性比前一句高,即如果轨道空了不管筐满不满,按下对应按钮啥也不会发生!

1.如果按0,且筐不为空,直接抓东西到流水线ans

2.如果按其他数字,先判断货架空不空(我用了字符串记录,判断是否到字符串尾即可)

        2.1如果货架x还有货品

                2.1.1 如果筐满了, 执行0操作, 否则不执行

                2.1.2 推货品入栈,同时idx[x]后移

3.输出流水线ans;

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
string item[N];
int idx[N];
stack<char> st;
vector<char> ans;

int main(){
    int n, m, s;
    cin>>n>>m>>s;
    for(int i = 1; i<= n; i++)
         cin>>item[i];
    memset(idx, 0, sizeof(idx));
    int x ;
    cin>>x;
    while(x != -1){
        if(!x){
            if(st.size()){
                ans.push_back(st.top());
                st.pop();
            }
        }
        else{
            if(idx[x] < item[x].length()){
                if(st.size() >= s) {
                    ans.push_back(st.top());
                    st.pop();
                }
                st.push(item[x][idx[x]++]);
            }
        }
        cin>>x;
    }
    for(int i = 0; i<ans.size(); i++)
        cout<<ans[i];
    return 0;
}

L2-038 病毒溯源

解题思路:特点是对于输出最小序列可以使用对输入时的病毒变异序列进行排序,这样找到的第一条最长的就是最小的最长序列,在寻找路径的时候可以用递归输出,开始每次记录路径会超时,后面记录了所有的路径尾巴会报错只有14分,我估计是是输出了非最小的(即使我对所有可能结果都进行了排序,还是出问题了)

#include <bits/stdc++.h>
#define PII pair<int, int> 
using namespace std;
const int N = 1e4+10;

//思路:如果最长链不唯一,则输出最小序列。
//可能长得像个树,考虑bfs,邻接表
//如何确定有几个头? st [], 然后遍历 
bool st[N];
vector<int> v[N];
int maxd = 0;
int path[N];
int tail;
void printP(int x){
    if(st[x]){
        printP(path[x]);
        cout<<' ';
    }
    cout<<x;
}
int main()
{
    int n, k, x;
    cin>>n;
    memset(st, false, sizeof(st));
    for(int i = 0; i<n; i++){
        cin>>k;
        for(int j = 0; j<k; j++){
            cin>>x;
            v[i].push_back(x);
            st[x] = true;
            path[x] = i;
        }
        sort(v[i].begin(), v[i].end());
    }
    int pos;
    for(int i = 0; i< n; i++)
        if(!st[i]){
            pos = i; break;
        }
    queue<PII> q;
    q.push(make_pair(pos, 1));
    while(q.size()){
        PII tmp  = q.front(); q.pop();
        if(tmp.second > maxd){
            maxd = tmp.second;
            tail = tmp.first; 
        }
        for(int i = 0; i<v[tmp.first].size(); i++){
            q.push(make_pair(v[tmp.first][i], tmp.second + 1));
        }
    }
    cout<<maxd<<endl;
    printP(tail);
    return 0;
}

L2-039 清点代码库

解题思路:STL,没什么难点,倒是有个地方很奇怪,一开始用的string 来存,直接getline,但是会错,然后用了vector一个一个存,不错了,但是看了一下去年用的就是string

AC代码:

#include <bits/stdc++.h>
#define PII pair<int, vector<int>> 
using namespace std;
const int N = 1e4+10;
PII p[N];
map<vector<int>, int> mp;
bool cmp(PII a, PII b){
    if(a.first != b.first) return a.first > b. first;
    return a.second < b.second;
}
int main()
{
    int n, m, x;
    cin>>n>>m;
    vector<int> tmp;
    for(int i = 0; i< n; i++){
        tmp.clear();
        for(int j = 0; j< m; j++)
        {
            cin>>x;
            tmp.push_back(x);
        }
        if(mp.find(tmp) == mp.end()) mp[tmp] = 1;
        else mp[tmp]++;
    }
    int idx = 0;
    for(auto it: mp)
        p[idx].first = it.second, p[idx++].second = it.first;
    sort(p, p+idx, cmp);
    cout<<idx<<endl;
    for(int i = 0; i< idx; i++)
    {
        cout<<p[i].first;
        for(int j = 0; j<p[i].second.size(); j++)
            cout<<' '<<p[i].second[j];
        if(i != idx-1)cout<<endl; 
    }
    return 0;
}

就很奇怪!!! (测试点4,6超时了)

歪歪歪,我刚刚发现我去年就没错出来,就是4,6不对哈哈哈哈哈哈哈哈哈,我真傻

这个是WA的代码

#include <bits/stdc++.h>
#include <sstream>
using namespace std;
const int N = 1e4+10;
map<string , int> mp;
map<string , int> cnmp;
struct node{
	int fp;
	string s;
	int cnt;
}p[N];
bool cmp(node a, node b)
{
	if(a.cnt != b.cnt) return a.cnt > b.cnt;
	else{
		stringstream ss(a.s);
		stringstream ss2(b.s);
    	int ta, tb;
    	ss >>ta;
    	ss2 >>tb;
    	while(ta == tb)
    	{
    		ss>>ta;
    		ss2>>tb;
    	}
    	return ta < tb;
	}
}
int main()
{
	int n, m;
	cin>>n>>m;
	getchar();
	for(int i = 1; i<= n; i++)
	{
		string s;
		getline(cin, s);
		if(mp.count(s) == 0) mp[s]++,cnmp[s] = i;
		else mp[s]++;
	}
	int cot = 0;
	for(map< string, int >::iterator it1 = mp.begin(); it1!=mp.end(); it1++)
	{
		p[cot].cnt = it1->second;
		p[cot].s = it1->first;
		p[cot++].fp = cnmp[it1->first];
	}
	sort(p, p+cot,cmp);
	cout<<cot<<endl;
	for(int i = 0; i<cot; i++)
	{
		cout<<p[i].cnt<<' '<<p[i].s ;
		if(i!=cot-1) cout<<endl;
	}
	return 0;
} 

L2-040 哲哲打游戏

解题思路:模拟,状态记录

#include <bits/stdc++.h>
using namespace std;
const int N  = 1e5+10;
vector<int> op[N];
int st[N];
int main()
{
    int cur = 1;
    int n, m;
    cin>>n>>m;
    int k, x;
    for(int i = 1; i<=n; i++){
        cin>>k;
        while(k--){
            cin>>x;
            op[i].push_back(x);
        }
    }
    while(m--){
        cin>>k>>x;
        if(!k){
            cur = op[cur][x-1];
        }
        else if(k == 1){
            cout<<cur<<endl;
            st[x] = cur;
        }
        else {
            cur = st[x];
        }
    }
    cout<<cur<<endl;
    return 0;
}

到这为止,终于追上去年的速度了!!!

现在是2023年4月18号,还有三天,加油加油加油!!!

L2-041 插松枝

解题思路:模拟题,使用STL,感觉本身不难关键难点在于理解流程还要代码别写错,调试好麻烦,特别是stack无法方便地遍历,为了方便我理清思路,很多小操作写成了函数。

下面是伪代码:(看个思路吧,写的也不大好)

1.小盒子有松针,优先取小盒子

        1.1松枝为空或者松针不大于已有的最上层松针,直接插

        1.2如果插满了,就输出+清空ans,同时跳转到1

        1.3不符合条件或者盒子空了结束1。

2.推送器sto取出来一根松针(只是front , 没有 pop没事,可以塞回去)

        2.1如果松枝为空或者松针不大于已有的最上层松针,直接插

                2.1.1如果插满了,就输出+清空ans,同时跳转到1

        2.2松枝不为空,且松针大大于已有的最上层松针

                2.2.1小盒子满了,则就输出+清空ans

                2.2.2小盒子没满,就放入小盒子

3.如果推送器sto不为空,就跳转到1一直循环。

4.如果小盒子不为空就一直循环,不符合条件或者松枝满了,就输出并清空ans,否则就插松枝。

5,若存在未完成的松枝,输出。

AC代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
vector<int> ans;
queue<int> sto;
stack <int> st;
int n, m, k;
void printans(){
     cout<<ans[0];
     for(int i = 1; i<ans.size(); i++)
        cout<<' '<<ans[i];
     ans.clear();
    cout<<endl;
}
void work1(){
    while( st.size() && ans.size() && ans.back() >= st.top() ){
         ans.push_back(st.top());
         st.pop();
         if(ans.size() == k) {
           printans();
           if(st.size()) ans.push_back(st.top()), st.pop();
        }
   }
}
int main()
{
    cin>>n>>m>>k;
    int x;
    for(int i  = 0; i<n; i++){
        cin>>x;  sto.push(x);
    }
    while(sto.size()){
        if(st.size()) work1();
        int tmp = sto.front();
        if( !ans.size() || tmp <= ans.back()){
            ans.push_back(tmp);
            sto.pop();
            if(ans.size() == k){
                 printans();
                 if(st.size()) ans.push_back(st.top()), st.pop();
            }
            continue;
        }
        if(ans.size() && tmp > ans.back()){
            if( st.size() >=  m) {
                 printans();
                 ans.push_back(st.top());
                 st.pop();
             }else {
                 st.push(tmp);
                 sto.pop();
             }
        }
         
    }
	while(st.size()){
    	if(ans.back() < st.top() || ans.size() == k)
			printans();
		ans.push_back(st.top());st.pop();
	}
    if(ans.size()) printans();
    return 0;
}

L2-042 老板的作息表

解题思路:自定义结构体,区间合并。

#include <bits/stdc++.h>
#define int long long 
using namespace std;
const int N = 1e5+10;
struct node{
    int h1, m1, s1, h2,m2, s2;
    int sum1 , sum2;
}p[N];
bool cmp(node a, node b){
    return a.sum1 < b.sum1;
}
signed main()
{
    int n;
    char c;
    cin>>n;
    for(int i = 0; i< n; i++){
        scanf("%d:%d:%d - %d:%d:%d", &p[i].h1, &p[i].m1, &p[i].s1, &p[i].h2, &p[i].m2, &p[i].s2);
        p[i].sum1 = p[i].h1*3600 + p[i].m1*60 + p[i].s1;
        p[i].sum2 = p[i].h2*3600 + p[i].m2*60 + p[i].s2;
    }
    sort(p, p + n, cmp);
    node cur = {0,0,0,0,0,0,0,0};
    for(int i = 0; i< n; i++){
      if(cur.sum2 < p[i].sum1){
          printf("%02d:%02d:%02d - %02d:%02d:%02d\n", cur.h2, cur.m2, cur.s2, p[i].h1, p[i].m1, p[i].s1);
      }
      cur.sum2 = p[i].sum2;
      cur.h2 = p[i].h2;cur.m2 = p[i].m2;cur.s2 = p[i].s2;
    }
    if(cur.sum2 != 23*3600 + 59*60 + 59){
        printf("%02d:%02d:%02d - 23:59:59\n", cur.h2, cur.m2, cur.s2);
    }
    return 0;
}

L2-043 龙龙送外卖

解题思路:dfs, 关键点在于标记,向上到达外卖站或者已经标记过的结点,就停止,返回长度*2,第一次交只过了14分,答案等于总长 - 要减去 最长的深度(最长的深度应该等于到外卖站的深度+到集合的最短距离)!

 AC代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5+10;
//无向无环图 == 树
//稠密图: 1e5 
int f[N];
bool st[N];
int maxd, ans = 0, p[N];
int pos = 0 ;
int dfs(int x, int d){
    if(p[x] || x == pos){
        maxd = max(maxd, d+p[x]);//因为来过这个点,所以p[x], d
        return d * 2;
    }
    int tmp = dfs(f[x], d+1);
    p[x] = p[f[x]] + 1;
    return tmp;
}
signed main(){
    int n, m, x;
    cin>>n>>m;
    memset(p, 0 , sizeof(p));
    for(int i = 1; i<= n; i++){
        cin>>f[i];
        if(f[i] == -1) pos = i;
    }
    for(int i =0; i< m; i++) {
        cin>>x;
        ans +=  dfs(x, 0);
        cout<<ans - maxd<<endl;
    }
    return 0;
}

WA代码:测试点(5,7)超时(优化方法,把到根的距离用dfs一起算了)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5+10;
//无向无环图 == 树
//稠密图: 1e5 
int f[N], p[N];
bool st[N];
int maxcur = 0;
int ans;
int pos = 0 ;
void dfs(int x, int d){
    if(!st[x]){
        st[x] = true;
        dfs(f[x], d+1);
    }
    else ans += d*2, maxcur = max(maxcur, p[x] + d);
}
int getroot(int x){
    if(x == pos) return 0;
    p[x] = getroot(f[x])+ 1;
    return p[x];
}
signed main(){
    int n, m, x;
    cin>>n>>m;
    memset(st,false, sizeof(st));
    memset(p, 0 , sizeof(p));
    for(int i = 1; i<= n; i++){
        cin>>f[i];
        if(f[i] == -1) pos = i;
    }
    for(int i = 1; i<= n; i++)
        if(!p[i]) getroot(i);
    
    st[pos] = true;
    for(int i =0; i< m; i++) {
        cin>>x;
        dfs(x, 0);
        cout<<ans - maxcur<<endl;
    }
    return 0;
}

L2-044 大众情人

解题思路:思路是对的,但是出现了一些初始化的问题没有考虑到,然后看了很多帖子还是不对,最后发现是初始化的问题!

AC代码:

#include <bits/stdc++.h>
#define PII pair<int, int>
// #define int long long
#define inf 1e9
using namespace std;
const int N  =550;
//多源最短路,算完距离感,再算异性缘(异性缘最好就是最大距离感最小的人)
//答案:找出两个两个性别中的大众情人
//500 * 500 *500 = 1e8,还可以
int g[N][N];
int f[N];
int sex[N];
int n;
void floyd(){
   for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
    
}
signed main()
{
    cin>>n;
   //初始化也很重要,不能简单地memset 
    for(int i = 1; i<= n;i++)
        for(int j = 1; j<= n; j++)
            if(i == j) g[i][j] = 0;
            else g[i][j] = inf;
   
    for(int i=1;i<=n;i++)
    {
        char op;cin>>op;
        sex[i]=(op=='M');
        int m;cin>>m;
        while(m--)
        {
            int fri,dis;
            scanf("%d:%d",&fri,&dis);
            g[i][fri]=dis;
        }
    }
    floyd();
    int ans1 = inf, ans2 = inf;
    memset(f, 0 ,sizeof(f));
  
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(sex[i]!=sex[j])
                f[i]=max(f[i],g[j][i]);
    
    for(int j = 0; j< 2; j++){
        int minx = 1e9;
        for(int i = 1; i<= n; i++)
            if(j == sex[i])
                minx = min(minx, f[i]);
        bool flag =  false;
        for(int i = 1; i<= n; i++)
            if(minx == f[i] && sex[i] == j){//测试点1,3
                if(flag) cout<<' ';
                else flag = true;
                cout<<i;
            }
        cout<<endl;
    }
    return 0;
}

初版,在调试后发现的一些坑点(AC的)

#include <bits/stdc++.h>
#define PII pair<int, int>
#define int long long
#define inf 1e9 //测试点3是1e9,0x3f3f3f会报错
using namespace std;
const int N  = 500+10;
//多源最短路,算完距离感,再算异性缘(异性缘最好就是最大距离感最小的人)
//答案:找出两个两个性别中的大众情人,要按性别分类,再排序
//500 * 500 *500 = 1e8,还可以
int g[N][N];
int f[N];
int sex[N];
vector<int> boy, girl;
int n;
void floyd(){
    for(int k = 1; k<= n; k++)
        for(int i = 1; i<=n; i++)
            for(int j = 1; j<= n; j++)
                g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
}
signed main()
{
    
    cin>>n;
    for(int i = 1; i<= n; i++) //测试点1是初始化
        for(int j = 1; j<= n; j++)
            if(i == j) g[i][j] = 0;
            else g[i][j] = inf;
    
    for(int i = 1 ; i<=n ;i++){
        int k,x,xx;
        char c;
        cin>>c>>k;
        if(c == 'M') sex[i] = 1;
        else sex[i] = 0;
        while(k--)
            cin>>x>>c>>g[i][x];
    }
    floyd();
    int ans1 = inf, ans2 = inf;
   memset(f, 0 ,sizeof(f));
    for(int i = 1; i<= n; i++){
        for(int j =1; j<= n; j++){
            if(sex[i] != sex[j])
                f[i] = max(f[i], g[j][i]);
        }
    }

    for(int i = 0; i<2; i++){
        int tmp = inf;
        for(int j = 1; j<= n; j++)
            if(i == sex[j])tmp = min(tmp, f[j]);
        bool flag = false;
        for(int j = 1; j<= n; j++)
            if(i == sex[j] && tmp == f[j]){
                if(flag) cout<<" ";
                else flag = true;
                cout<<j;
            }
        cout<<endl;
    }
    return 0;
}

 

L2到这里就完结拉,虽然有一道冰岛人没做出来,但是不纠结了!!下次再填坑吧~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
接入第三方登录是让用户方便快捷地使用已有账号登录你的网站或应用程序,提高用户体验的一种方式。本文将介绍如何使用 PHP 实现微信公众号第三方登录。 1. 获取微信授权 首先,需要获取微信用户的授权。具体步骤如下: 1)引导用户打开微信授权页面: ```php $appid = 'your_appid'; $redirect_uri = urlencode('http://yourdomain.com/callback.php'); $scope = 'snsapi_userinfo'; $url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=$appid&redirect_uri=$redirect_uri&response_type=code&scope=$scope&state=STATE#wechat_redirect"; header("Location: $url"); ``` 其中,`$appid` 是你的微信公众号的 AppID,`$redirect_uri` 是授权后回调的 URL,`$scope` 是授权作用域,可以是 `snsapi_base` 或 `snsapi_userinfo`,`$state` 是自定义参数,用于防止 CSRF 攻击。 2)获取授权码: 用户同意授权后,会重定向到 `$redirect_uri` 指定的 URL,带上授权码 `code` 和 `state` 参数。 ```php $code = $_GET['code']; $state = $_GET['state']; ``` 3)获取 access_token 和 openid: 使用授权码 `code` 获取 `access_token` 和 `openid`。 ```php $access_token_url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=$appid&secret=$secret&code=$code&grant_type=authorization_code"; $response = file_get_contents($access_token_url); $result = json_decode($response, true); $access_token = $result['access_token']; $openid = $result['openid']; ``` 其中,`$secret` 是你的微信公众号的 AppSecret。 2. 获取用户信息 获取到 `access_token` 和 `openid` 后,可以使用以下代码获取用户信息: ```php $userinfo_url = "https://api.weixin.qq.com/sns/userinfo?access_token=$access_token&openid=$openid&lang=zh_CN"; $response = file_get_contents($userinfo_url); $userinfo = json_decode($response, true); ``` 其中,`$userinfo` 包含用户的昵称、头像等信息。 3. 将用户信息保存到数据库 最后,将获取到的用户信息保存到数据库中,以便下次使用时快速登录。 ```php // 连接数据库 $con = mysqli_connect('localhost', 'username', 'password', 'database'); mysqli_set_charset($con, "utf8"); // 查询用户是否已存在 $sql = "SELECT * FROM users WHERE openid='$openid'"; $result = mysqli_query($con, $sql); if (mysqli_num_rows($result) == 0) { // 用户不存在,插入新用户信息 $nickname = mysqli_real_escape_string($con, $userinfo['nickname']); $headimgurl = mysqli_real_escape_string($con, $userinfo['headimgurl']); $sql = "INSERT INTO users (openid, nickname, headimgurl) VALUES ('$openid', '$nickname', '$headimgurl')"; mysqli_query($con, $sql); } // 保存用户登录状态 $_SESSION['openid'] = $openid; ``` 以上就是使用 PHP 实现微信公众号第三方登录的步骤。需要注意的是,为了确保安全性,应该对用户输入的数据进行过滤和验证,防止 SQL 注入和 XSS 攻击等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值