ZZU天梯选拔赛复盘

问题 A: A.博弈论 [ABC148F] Playing Tag on Tree

题目描述

有一个n个节点的树,刚开始邱宇站在x号点,妹妹站在y号点。
邱宇先手,两人交替地行动。每次需要移动到相邻的位置。如果两人在某一点相遇,则游戏结束。
邱宇希望游戏尽量晚地结束,妹妹希望游戏尽量早地结束。若两人使用最优策略,则妹妹会移动多少次? 

输入

第一行三个数,分别是节点数量n,邱宇的起点x和妹妹的起点y。
接下来n-1行,每行两个数表示树的一条边。
数据保证是一颗树,2<=n<=100000,x!=y。

输出
输出一个非负整数表示妹妹将会移动多少次。

样例输入
样例输入1:
5 4 1
1 2
2 3
3 4
3 5
样例输入2:
5 4 5
1 2
1 3
1 4
1 5
样例输入3:
2 1 2
1 2
样例输入4:
9 6 1
1 2
2 3
3 4
4 5
5 6
4 7
7 8
8 9

样例输出
样例输出1:
2
样例输出2:
1
样例输出3:
0
样例输出4:
5
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
const int N = 1e5 + 7;
int n, u, v, x, y, vis[N], ans[N], m; // 声明变量n, u, v, x, y, vis数组, ans数组, m
vector<int> w[N]; // w为大小为N的整型向量数组
//若一个点到u的距离小于它到v的距离 那么T就不会在这里被A追上 
//u是T的起点 v是A的起点 
void dfs(int a, int b, int c){ // 定义DFS函数,参数为当前节点编号a,距离b,标志位c
    if(c) 
        vis[a] = b; // 如果标志位c为1,将当前节点标记为已访问,并记录距离在vis数组中
    else 
        ans[a] = b; // 如果标志位c为0,记录距离在ans数组中
    for(int i = 0; i < w[a].size(); i++){ // 遍历当前节点a的相邻节点
        if(c && !vis[w[a][i]] && w[a][i] != v)  // 如果标志位c为1且相邻节点未被访问过且不等于目标节点v
            dfs(w[a][i], b + 1, c); // 以相邻节点为新的当前节点,距离b+1,标志位c,进行递归调用dfs函数
        else if(!c && !ans[w[a][i]] && w[a][i] != u)  // 如果标志位c为0且相邻节点未被访问过且不等于起始节点u
            dfs(w[a][i], b + 1, c); // 以相邻节点为新的当前节点,距离b+1,标志位c,进行递归调用dfs函数
    }
}
int main(){
    IOS; // 同步输入输出流
    cin >> n >> u >> v; // 输入n, u, v
    for(int i = 1; i < n; i++) // 循环读入n-1条边的信息
        cin >> x >> y, w[x].push_back(y), w[y].push_back(x); // 将边的两个端点信息加入到w数组中
    dfs(v, 0, 1), dfs(u, 0, 0);  // 第一次DFS,计算从目标节点v到各个节点的距离;第二次DFS,计算从起始节点u到各个节点的距离
    for(int i = 1; i <= n; i++)  // 遍历所有节点
        if(vis[i] > ans[i]) // 如果从目标节点到达某节点的距离大于从起始节点到达该节点的距离
//        vis[i]记录的是i到v的距离 
            m = max(m, vis[i]); // 更新最大距离m
    printf("%d", m - 1); // 输出最大距离减去1
    return 0;
}

问题 B: B.分发礼物 [ABC148C] Snack

题目描述

codeforces.com/problemset/problem/4/A分西瓜这道题想必大部分人已经做过了。
邱宇正在和实验室的大伙分西瓜。已知要分西瓜的总人数将会是A或者B(都有可能),邱宇希望平均地分配给每个朋友整数斤的西瓜。
请你输出最少需要多少斤西瓜,才能满足对于两种情况都能满足条件地分配。

输入

输入一行两个整数A,B。
保证1<=A,B<=10^5,A不等于B

输出

输出一个整数表示你的答案。

样例输入
样例输入1:
2 3
样例输入2:
123 456
样例输入3:
100000 99999

样例输出
样例输出1:
6
样例输出2:
18696
样例输出3:
9999900000
#include <bits/stdc++.h>
#define int long long
using namespace std;
void solve(){
	int a,b;cin>>a>>b;
	cout<<a*b/__gcd(a,b);
	return ;
}
signed main(){
	int t=1;
	while(t--)solve();
	return 0;
} 

问题 C: C.石头剪刀布 [ABC149D] Prediction and Restriction

题目描述

邱宇正在和妹妹玩石头剪刀布。如果用石头获胜,他将会获得R分。如果用剪刀获胜,他将获得S分。如果用布获胜,他将获得P分。如果输了或者平局将不得分也不扣分。
由于妹妹不太聪明,她将会按照特定的字符串出石头,剪刀或布。具体地,数据会给你一个字符串T,字符串的第i位是r,p,s时,妹妹将会在第i轮出石头,布或者剪刀。
虽然优势很大,但是邱宇也有一点点劣势:在前K轮中,可以任意地出。但是在K轮之后,他不能出的和第(i-K)轮一样。
例如第1轮出了石头,K=3,那么他第4轮将不能再出石头。
优势如此之大,邱宇想让你帮他算算他最多能获得多少分?

输入

第一行两个正整数N,K表示玩多少局和限制因素K。
第二行三个正整数R,S,P分别表示出石头、剪刀或者布,并且获胜时,邱宇能获得的分数。
第三行一个长为N的字符串表示妹妹的每一轮的出法。
保证2<=N<=10^5,1<=K<=N-1,1<=R,S,P<=10^4,字符串的长度恰好为N,字符串中只包含字符r,p,s。

输出

输出最多能获得几分。

样例输入
样例输入1:
5 2
8 7 6
rsrpr
样例输入2:
7 1
100 10 1
ssssppr
样例输入3:
30 5
325 234 123
rspsspspsrpspsppprpsprpssprpsr

样例输出
样例输出1:
27
样例输出2:
211
样例输出3:
4996

#include <bits/stdc++.h>
using namespace std;
//读清楚题
void solve() {
    int n, k;
    cin >> n >> k;
    int a, b, c;cin >> a >> b >> c;
    //出石头 剪刀 布且获胜
    //r s p   那妹妹要出
    //s p r
    string s;cin >> s;
    s=' '+s; 
    int ans = 0;
    for (int i = 1; i <= k; i++) {
        if (s[i] == 'r') ans += c;
        if (s[i] == 's') ans += a;
        if (s[i] == 'p') ans += b;
    }
    for (int i = k+1; i <=n; i++) {
        if (s[i] == s[i - k]) {
            s[i] = 'x'; //如果重复就还称x 使得下一次不会重复 
        } else {
            if (s[i] == 'r') ans += c;
            if (s[i] == 's') ans += a;
            if (s[i] == 'p') ans += b;
        }
    }
    cout << ans << '\n';
}

int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t = 1;
    while (t--)solve();
    return 0;
}

问题 D: D.异或和的和 [ABC147D] Xor Sum 4

题目描述

这是一个简单的异或和的和的问题。
给你N个数字,求ΣAi XOR Aj(i<j)对10^9+7的余数。其中XOR表示亦或。

输入

第一行一个整数N。
第二行N个整数表示数组A。
保证2<=N<=3*10^5,0<=Ai<2^60。

输出

 输出一个整数表示你的答案。

样例输入
样例输入1:
3
1 2 3
样例输入2:
10
3 1 4 1 5 9 2 6 5 3
样例输入3:
10
3 14 159 2653 58979 323846 2643383 27950288 419716939 9375105820

样例输出
样例输出1:
6
样例解释1:
(1 XOR 2)+(1 XOR 3)+(2 XOR 3)=3+2+1=6
样例输出2:
237
样例输出3:
103715602
#include <bits/stdc++.h>>
#define int long long
const int mod = 1e9+7;
using namespace std;
const int N = 3e5+7;
int a[N];
//a开到了2^60说明用位运算了 

void solve(){
    int n;cin >> n;
    for (int i = 1; i <= n; i++)cin >> a[i];
    
    int ans = 0;
    
    for (int i = 0; i < 60; i++){ //对于每一个位置 
        int cnt = 0;            
        for (int j = 1; j <= n; j++) {
            if (a[j] & (1ll << i)) {//如果有一个这个位置是1cnt就++
			 
                cnt++;//相同
                
            }//意思就是如果是1的话 
        }//(2的i次方)*cnt *(n-cnt) 
        ans=(ans + ((1ll << i)%mod*cnt%mod * (n - cnt) % mod))%mod;//一个位置上1的个数乘以0的个数实际上可以用来表示这些数两两异或异或的一种形式 
    }
    cout << ans << '\n';
}

signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t=1; 
    while(t--)solve();
    return 0;
}

问题 E: E.吃饼干 [ABC149B] Greedy Takahashi

题目描述

邱宇有A个饼干,妹妹有B个饼干。
妹妹将会循环K次以下动作:

  • 如果邱宇还有饼干,则吃邱宇的其中一块
  • 否则,如果自己还有饼干,吃自己的其中一块
  • 否则,什么也不做

请问最后邱宇和妹妹各自还剩多少饼干。

输入

输入一行三个整数:A,B,K
保证0<=A,B,K<=10^12(ABK三个数都满足这个条件)

输出

输出一行两个整数表示答案

样例输入
2 3 3

样例输出
0 2
#include <bits/stdc++.h>
#define int long long
using namespace std;
void solve(){
	int a,b,k;cin>>a>>b>>k;
	if(a>=k){cout<<a-k<<" "<<b;return ;}
	if(b>=k-a){cout<<"0 "<<b+a-k;return ;}
	cout<<"0 0";
	return ;
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int t=1;
	while(t--)solve();
	return 0;
} 

问题 F: F.abs(全排列-全排列) [ABC150C] Count Order

题目描述

全排列和字典序应该不用再介绍了。。。
总而言之,你有两个长为N的排列,他们在全排列中都有一席之地,你需要输出他们在字典序排列的全排列中的排名之差。
123和321谁排第一呢?出题人不想管了,所以决定让你abs一下。

输入

第一行一个正整数N
第二行一个长为N的排列表示排列A
第三行一个长为N的排列表示排列B
数据保证2<=n<=8

输出

输出一个非负整数表示他们排名的差值

样例输入
样例输入1:
3
1 3 2
3 1 2
样例输入2:
8
7 3 5 4 2 1 6 8
3 8 2 5 4 6 7 1
样例输入3:
3
1 2 3
1 2 3

样例输出
样例输出1:
3
样例输出2:
17517
样例输出3:
0
#include <bits/stdc++.h>
using namespace std;

void solve(){
    int n;
    cin >> n;
    string a, b;
    for(int i=0;i<n;i++){char ch;cin>>ch;a+=ch;}
    for(int i=0;i<n;i++){char ch;cin>>ch;b+=ch;}
    string c = a;
    sort(c.begin(), c.end());
    int cnt = 0;
    int ans1 = 0;int ans2 = 0;

    do {//记得要用do while语句进入循环
        cnt++;
        if (c == a) ans1 = cnt;
        if (c == b) ans2 = cnt;
        if (ans1 && ans2) break;
    } while (next_permutation(c.begin(), c.end()));
    cout << abs(ans1 - ans2)<< '\n';//记得加abs()
}

int main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t = 1;
    while(t--) solve();
    return 0;
}

问题 G: G.重排 [ABC163E] Active Infants

题目描述

一个长为n的数组,你需要将其重新排列,使得总贡献最大。
其中一个数字ax如果之前排在了第x个位置,移动后排在了第y个位置,则会获得Ax*|x-y|的贡献。

输入

第一行一个正整数n。
接下来一行n个数,表示初始的数组。
保证2<=n<=2000,1<=ai<=10^9

输出

一行一个整数表示最大的总贡献。

样例输入
样例输入1:
4
1 3 4 2
样例输入2:
6
5 5 6 1 1 1
样例输入3:
6
8 6 9 1 2 1

样例输出
样例输出1:
20
样例解释1:
将a1移动到a3,a2移动到a4,a3移动到a1,a4移动到a2,则会获得1*|1-3|+3*|2-4|+4*|3-1|+2*|4-2|=20
样例输出2:
58
样例输出3:
85
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N = 2e3+9 ;
const ll mod = 1e9+7 ;
const ll INF = 1e18 ;
ll Abs( ll x ){ return x < 0 ? -x : x ; }
ll dp[ N ][ N ] , n ;//dp[i][j]表示将区间[i, j]的数字重新排序后所能获得的最大贡献值 
//只在这[l,r]范围中调整 
pair<ll,ll>a[ N ] ;

void solve(){
    cin >> n ; 
    for( int i = 1 ; i <= n ; i ++ ){
        cin >> a[ i ].first ; 
        a[ i ].second = i ;
    }
    
    sort( a+1 , a+1+n ) ;
    
    for( int len = 1 ; len <= n ; len ++ ) {
        for( int l = 1 , r = len ; r <= n ; l++ , r ++ ) {//左右端点  
            if( l == r ) {// 左端点==右端点 
                dp[l][r] = a[len].first * Abs(l - a[len].second) ;
            } else {
                dp[ l ][ r ] = max( dp[l+1][r] + a[len].first * Abs(l - a[len].second),
                                    dp[l][r-1] + a[len].first * Abs(r - a[len].second) );//移动到两个极端 看看哪个大 
            }
        }
    }
    
    cout << dp[1][n] << "\n" ;
}

int main(){ios::sync_with_stdio(false) ; cin.tie(0) ; cout.tie(0) ;
    
    ll tt = 1 ; //cin >> tt ;
    while( tt-- ) solve() ;
    
    return 0 ;
}

问题 H: H.期望 [ABC149F] Surrounded Nodes

题目描述

邱宇正在给一棵树涂色。每个顶点有1/2的概率被涂成黑色,有1/2的概率被涂成白色。
对于一个涂色的结果,他划定了子树X表示联通所有黑色点的最小子图叫做最小黑点子树
希望你帮他求出最小黑点子树中包含白点的数量的期望值对10^9+7取模。
(幻视小黑子)

输入

第一行输入一个正整数N。
接下来N-1行,每行两个正整数表示这条无向边边所连的两个点。
保证2<=N<=2*10^5,给出的图是一棵树。

 

输出

输出一个值表示包含白点的数量的期望值。

样例输入
样例输入1:
3
1 2
2 3
样例输入2:
4
1 2
2 3
3 4
样例输入3:
4
1 2
1 3
1 4
样例输入4:
7
4 7
3 1
2 6
5 2
7 1
2 7

样例输出
样例输出1:
125000001
样例输出2:
375000003
样例输出3:
250000002
样例输出4:
570312505

问题 I: I.删数字 [ABC148D] Brick Break

题目描述

给你一个n个数字的数组a,你需要尽可能少的删除数字,使得剩下的数字都满足ai=i,输出最少要删几个数。
由于你可以至多删去 n - 1 个数,如果无法满足通知条件,请输出-1。

输入

第一行一个正整数N
接下来一行n个整数表示a数组。
保证1 <= n <= 200000,1 <= ai <= n 。

输出

输出一个数字,即最少删除的数量。如果无解输出 -1

样例输入
样例输入1:
3
2 1 2
样例输入2:
3
2 2 2
样例输入3:
10
3 1 4 1 5 9 2 6 5 3
样例输入4:
1
1

样例输出
样例输出1:
1
样例解释1:
删除第一个数,剩下1 2,满足要求。
样例输出2:
-1
样例输出3:
7
样例输出4:
0、
样例解释4:
不需要删除数字即可满足条件。
#include <bits/stdc++.h>
#define int long long
const int mod=1e9+7;
using namespace std;
const int N=3e5+7;
vector<int>v;
void solve(){
    int n;cin>>n;
    v.push_back(0);//垫一下 
    for(int i=1;i<=n;i++){int a;cin>>a;v.push_back(a);}//输入数字 
    int  pt=1;//从1开始每个数 
    int cnt=0;//计算删去的个数 
    int i=1;
    while(i){
    	if(v[i]==pt)pt++;//看看最后枚举到哪个数了 
    	i++;
    	if(i==v.size())break;
	}//最后该是pt了但是pt没找到 所有是(pt-1) 
	cout<<(pt==1?-1:n-(pt-1));
}
signed  main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t = 1;
    while(t--) solve();
    return 0;
}

问题 J: J.网格 [ABC147E] Balanced Path

题目描述

给定 n 行,m 列的网格。第i行第j个格子上面写有两个数字 A[i][j] 和 B[i][j] 。
邱宇将从左上角走到右下角(第一行第一列走到第n行第m列),每次只能往下走一行或者往右走一格且不能走出去。在每一个格子上,他将给A[i][j]和B[i][j]一个涂成红色,另一个填黑色。
在所有有可能的路径与涂色方案中,abs(黑色数字之和-红色数字之和)最小是多少?

输入

第一行两个正整数表示行和列n,m
接下来n行,每行m个数表示格子上的数字A[i][j]
接下来又有n行,每行m个数表示格子上的数字B[i][j]
数据保证2 <= n,m <= 80,0 <= A[i][j], B[i][j] <= 80

输出

输出最小的两种颜色数字之和的差值。

样例输入
样例输入1:
2 2
1 2
3 4
3 4
2 1
样例输入2:
2 3
1 10 80
80 10 1
1 2 3
4 5 6

样例输出
样例输出1:
0
样例输出2:
2

提示

样例1:


如图所示。
黑: 1 + 2 + 4 = 7
白: 3 + 3 + 1 = 7
不和谐值为 7。
样例2:
略。

 

 

 

#include <bits/stdc++.h>
using namespace std;
int n,m;
const int N=86;
int a[N][N];
int b[N][N];
int c[N][N];
bool dp[N][N][30000];//表示走到(i,j)点红色总和减蓝色总和的值为k是否能成立 
void solve(){
	int n,m;cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a[i][j];
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>b[i][j];
			c[i][j]=a[i][j]-b[i][j];
		}
	}
	dp[0][0][12800]=1;//界外的--0肯定可以 
	dp[1][0][12800]=1;
	dp[0][1][12800]=1;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			for (int k = 1; k <= 12800*2; k++) {
				dp[i][j][k] = (dp[i-1][j][k+c[i][j]]|dp[i-1][j][k-c[i][j]])|(dp[i][j-1][k+c[i][j]]|dp[i][j-1][k-c[i][j]]);
			}
		}
	}
	
	int ans=0;
	for (int k = 12800; k <= 12800*2; k++)	{//正数 
		if (dp[n][m][k]) {
			ans = k - 12800;
			break;
		}
	}
	
	for (int k = 12800; k >= 0; k--) {//负数 
		if (dp[n][m][k]) {
			ans = min(ans, 12800 - k);//减去的越大 剩余的越小 
			break;
		}
	}
	cout<<ans; 
	return ;
}
int main(){
	int t=1;
	while(t--)solve();
	return 0;
} 

 

问题 K: K.个数是和的余数 [ABC146E] Rem of Sum is Num

题目描述

给一个长度为n的正整数序列A和一个正整数K。
求出有多少A的子串,满足该子串元素的和除以 K 的余数,等于它元素的个数。
如果两个子串是从不同的位置取的,即使他们元素都一样,我们也认为它们是不同的子串。

输入

第一行两个正整数n,K
第二行n个整数表示A数组
保证1 <= n <= 2*10^5,1 <= K, Ai <= 10^9

输出

输出满足条件的子串数量。

样例输入
样例输入1:
5 4
1 4 2 3 5
样例输入2:
8 4
4 2 4 2 4 2 4 2
样例输入3:
10 7
14 15 92 65 35 89 79 32 38 46

样例输出
样例输出1:
4
样例解释1:
[1], [4 2], [1 4 2] 和 [5] 。总计4个。 
样例输出2:
7
样例解释2:
4 个 [4, 2],3 个 [2, 4] 。总计 7 个。
样例输出3:
8
#include <bits/stdc++.h>>
using namespace std;
int val[200005];
unordered_map <int, int> cnt;//表示值为(sum-i)%k的个数 
int main()
{
	int n, k;
	scanf("%d%d", &n, &k);
	long long ans = 0, sum = 0;
	
	val[0] = 0, cnt[0]++;
	for (int i = 1; i <= n; i++)
	{
		int x;
		scanf("%d", &x), x %= k, sum += x;
		
		val[i] = ((sum - i) % k + k) % k; 
		
		if (i >= k) cnt[val[i - k]]--;//超出区间的范围了要删除 
		ans += cnt[val[i]];
		cnt[val[i]]++;
	}
	cout << ans;
	return 0;
}

 

问题 L: L.和差 [ABC147F] Sum Difference

题目描述

邱宇和妹妹正在玩游戏。刚开始有一个长度为 n 的整数序列 A满足 A[1] = X, A[i+1] = A[i] + D
邱宇会从中拿一些元素(可以是全拿或者全都不拿),妹妹会拿走剩下的。
请问邱宇和妹妹拿走的数字之和的差值有多少种可能。

输入

一行三个整数n,X,D

保证-10^8 <= X, D <= 10^8
1 <= n <= 2*10^5

输出

选取数字之差有多少种可能。

样例输入
样例输入1:
3 4 2

样例输入2:
2 3 -3

样例输入3:
100 14 20

样例输出
样例输出1:
8
样例解释1:
样例1:
A数组是 (4, 6, 8)。
邱宇有8种方式拿数字。
S - T的值有可能是-18, -10 ,-6, -2, 2, 6, 10 和 18,所以有 8 种可能的值。
样例输出2:
2
样例输出3:
49805

  • 25
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值