2025年寒假ACM练习3

目录

A: 小白鼠

 B: 放苹果

 C: gcd 区间

 D: 找宝箱

 E: 游船出租

F: 数字交换

 G: 搬水果

H: 打牌

 I: 狮子座的失眠

J: 狮子座的简单统计题

 K: 狮子座的复杂统计题

 L: 狮子座的水题

 M: 幸运数

 N: 跳跃版图

O: 耶路撒冷战役

P: Fy's dota2

Q: 河畔军训

R: 小B旅游

 S: 括号匹配

 T: 正常血压

 U: 三进制回文数

 V: hy的战犯评级(Easy)

W: hy的战犯评级(Hard)


A: 小白鼠

N只小白鼠(1 <= N <= 100),每只鼠头上戴着一顶有颜色的帽子。
现在称出每只白鼠的重量,要求按照白鼠重量从大到小的顺序输出它们头上帽子的颜色。
帽子的颜色用“red”,“blue”等字符串来表示。
不同的小白鼠可以戴相同颜色的帽子。白鼠的重量用整数表示。

输入

多案例输入,每个案例的输入第一行为一个整数N,表示小白鼠的数目。
下面有N行,每行是一只白鼠的信息。第一个为不大于100的正整数,表示白鼠的重量;
第二个为字符串,表示白鼠的帽子颜色,字符串长度不超过10个字符。

注意:白鼠的重量各不相同。

输出

每个案例按照白鼠的重量从大到小的顺序输出白鼠的帽子颜色。

样例输入 Copy
3
30 red
50 blue
40 green
样例输出 Copy
blue
green
red
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <algorithm>
#include <cstring>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;
const int N = 1e3 + 5;
const ll M = 1e9 + 7;
struct stu
{
    int b;
    char c[15];
}a[105];
bool com(stu a, stu b)
{
    return a.b > b.b;
}
void solve(){
    int n;
    while (~scanf("%d", &n))
    {
        for (int i = 0; i < n; i++)
            scanf("%d %s", &a[i].b, a[i].c);
        sort(a, a + n, com);
        for (int i = 0; i < n; i++)
            printf("%s\n", a[i].c);
    }
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    solve();
    return 0;
}

 B: 放苹果

把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?
(用K表示)5,1,1和1,5,1 是同一种分法。

输入

每行均包含二个整数M和N,以空格分开。1<=M,N<=10。

输出

对输入的每组数据M和N,用一行输出相应的K。

样例输入 Copy
7 3
样例输出 Copy
8
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 + 5;
int fun(int m,int n){
    if(m==0||n==1){
        return 1;
    }
    if(m<n){
        return fun(m,m);
    }
    else{
        return fun(m,n-1)+fun(m-n,n);
    }
}
void solve(){
    int m,n;
    while(cin>>m>>n){
        cout<<fun(m,n)<<"\n";
    }
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    solve();
    return 0;
}

 C: gcd 区间

给定一行 n 个正整数 a[1]..a[n]。

m 次询问,每次询问给定一个区间[L,R],输出 a[L]..a[R]的最大公因数。

输入

第一行两个整数 n,m。

第二行 n 个整数表示 a[1]..a[n]。

以下 m 行,每行 2 个整数表示询问区间的左右端点。

保证输入数据合法。

1 <= n <= 1000,1 <= m <= 1,000,000 0 < 数字大小 <= 1,000,000,000

输出

共 m 行,每行表示一个询问的答案。

样例输入 Copy
5 3
4 12 3 6 7
1 3
2 3
5 5
样例输出 Copy
1
3
7
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <algorithm>
#include <cstring>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;
const int N = 1e3 + 5;
const ll M = 1e9 + 7;
int a[N][N];
int gcd(int a,int b) {
    return b>0 ? gcd(b,a%b):a;
}
void solve(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i][i];
    }
    for(int i=1;i<n;i++){
        for(int j=i+1;j<=n;j++){
            a[i][j]=gcd(a[i][j-1],a[j][j]);
        }
    }
    while(m--){
        int x,y;
        cin>>x>>y;
        cout<<a[x][y]<<"\n";
    }
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    solve();
    return 0;
}

 D: 找宝箱

作为一个强迫症患者,小明在走游戏里的迷宫时一定要把所有的宝箱收集齐才肯罢休。

现在给你一个 N×M 的迷宫,里面有障碍、空地和宝箱,小明在某个起始点,每一步小明可以往上、下、左、右走,当然前提是没有走出迷宫并且走到的点不是障碍。如果小明走到了某个为宝箱的点,那么这个宝箱就被他收集到了,然后此处变为空地。

现在你需要计算小明最少需要走多少步才能收集齐所有的宝箱。

输入

输入共有两行。 

第一行一个两个正整数 N 和 M,表示迷宫大小。 

接下来 N 行,每行 M 个整数,第 i+1 行的第 j 个整数表示迷宫第 i 行第 j 列的情况, 0 表示空地,-1 表示障碍,1 表示宝箱,2 表示小明的起始点。保证 2 只有一个。 

1≤N,M≤100,宝箱个数不超过5个。

输出

一行一个整数,表示小明最少的步数。如果无法收集齐所有宝箱,输出-1。

样例输入 Copy
3 5
1 -1 1 -1 2
0 -1 0 -1 0
0 0 0 0 0
样例输出 Copy
12
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <list>
#include <deque>
#include <bitset>
#include <unordered_set> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const int N = 3e3+10;
const int M = 1e9+7;
const int inf = 0x3fffffff;
const int P = 13331;
bool st[105][105][32];
int n,m; 
int dx[]={-1,0,1,0};
int dy[]={0,-1,0,1};
struct S{
    int x,y;
    int st;//状态码 
    int ss;
};
void solve(){
    cin>>n>>m;
    vector<vector<int>> a(n,vector<int>(m));
    vector<vector<int>> b(n,vector<int>(m,-1));//存宝箱编号 
    vector<pair<int,int>> c;//收集宝箱坐标,0~size-1 
    int x=-1,y=-1;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>a[i][j];
            if(a[i][j]==2){
                x=i;
                y=j;
            }
            else if(a[i][j]==1){
                c.push_back({i,j});
                b[i][j]=c.size()-1;
            }
        }
    }
    int k=c.size();
    if(k==0){
        cout<<"0\n";
        return;
    } 
    queue<S> q;
    q.push({x, y,0,0});
    st[x][y][0]=true;
    int ans=-1;
    int s=(1<<k)-1;//全1 
    while(!q.empty()){
        auto t=q.front();
        q.pop();
        if(t.st==s){
            cout<<t.ss<<"\n";
            return;
        }
        for(int i=0;i<4;i++){
            int xx=dx[i]+t.x;
            int yy=dy[i]+t.y;
            if(xx<0||xx>=n||yy<0||yy>=m||a[xx][yy]==-1){
                continue;
            }
            int sst=t.st;
            int id=b[xx][yy];
            if(id!=-1){
                if(!(sst&(1<<id))){
                    sst|=(1<<id);
                }
            } 
            if(!st[xx][yy][sst]){
                st[xx][yy][sst]=true;
                q.push({xx,yy,sst,t.ss+1});
            } 
        }
    } 
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    //int T;cin>>T;for(int i=1;i<=T;i++)
    solve();
    return 0;
}

 E: 游船出租

现有公园游船租赁处请你编写一个租船管理系统。
当游客租船时,管理员输入船号并按下S键,系统开始计时;
当游客还船时,管理员输入船号并按下E键,系统结束计时。
船号为不超过100的正整数。当管理员将0作为船号输入时,
表示一天租船工作结束,系统应输出当天的游客租船次数和平均租船时间。    
 注意:由于线路偶尔会有故障,可能出现不完整的纪录,即只有租船没有还船,
或者只有还船没有租船的纪录,系统应能自动忽略这种无效纪录。
[注意]:每天的船只互不影响,比如第一天租了船1没有归还,第二天船1应该按照没有借处理。

输入

测试输入包含若干测试用例,每个测试用例为一整天的租船纪录,格式为:
船号(1~100) 键值(S或E) 发生时间(小时:分钟)
每一天的记录保证按时间递增的顺序给出。当读到船号为-1时,全部输入结束,相应的结果不要输出。

输出

对每个测试用例输出1行,即当天的游客租船次数和平均租船时间(以分钟为单位的精确到个位的整数时间,向上取整)。

样例输入 Copy
1 S 08:10
2 S 08:35
1 E 10:00
2 E 13:16
0 S 17:00
0 S 17:00
3 E 08:10
1 S 08:20
2 S 09:00
1 E 09:20
0 E 17:00
-1
样例输出 Copy
2 196
0 0
1 60
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <list>
#include <deque>
#include <bitset>
#include <unordered_set>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const int N = 3e3+10;
const int M = 1e9+7;
const int inf = 0x3fffffff;
const int P = 13331;
void solve(){
    int n;
    unordered_map<int ,string> mp;
    vector<int> s;
    while(cin>>n&&n!=-1){
        string op,t;
        cin>>op>>t;
        if(n==0){
            int k=s.size();
            if(k==0){
                cout<<"0 0\n";
            }
            else{
                int ss=0;
                for(auto i:s){
                    ss+=i;
                }
                cout<<k<<" "<<(ss+k-1)/k<<"\n";
            }
            mp.clear();
            s.clear();
        }
        else{
            if(op=="S"){
                if(mp[n]==""){
                    mp[n]=t;
                }
            }
            else{
                if(mp[n]!=""){
                    string a=mp[n];
                    int t1=((a[0]-'0')*10+a[1]-'0')*60+((a[3]-'0')*10+a[4]-'0');
                    int t2=((t[0]-'0')*10+t[1]-'0')*60+((t[3]-'0')*10+t[4]-'0');
                    s.push_back(t2-t1);
                    mp[n]="";
                }
            }
        }
    }
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    //int T;cin>>T;for(int i=1;i<=T;i++)
    solve();
    return 0;
}

F: 数字交换

输入一个数n,然后输入n个数值各不相同,调换数组中最大和最小的两个数,然后输出。

输入

测试数据有多组,输入n(1<=n<=20),接着输入n个数。

输出

对于每组输入,输出交换后的结果。

样例输入 Copy
2
1 3
样例输出 Copy
3 1

#include<stdio.h>
int main() {
    int i, t, max, min, a[25], n;
    max = min = 0;
    while (scanf("%d", & n) != EOF) {
        for (i = 0; i < n; i++) {
            scanf("%d", & a[i]);
            if (a[i] > a[max])
                max = i;
            else
            if (a[i] < a[min])
                min = i;
        }
        t = a[max];
        a[max] = a[min];
        a[min] = t;
        max = min = 0;
        for (i = 0; i < n; i++)
            printf("%d ", a[i]);
        printf("\n");
    }
    return 0;
}

 G: 搬水果

在一个果园里,小明已经将所有的水果打了下来,并按水果的不同种类分成了若干堆,小明决定把所有的水果合成一堆。
每一次合并,小明可以把两堆水果合并到一起,消耗的体力等于两堆水果的重量之和。
当然经过 n‐1 次合并之后,就变成一堆了。小明在合并水果时总共消耗的体力等于每次合并所耗体力之和。
假定每个水果重量都为 1,并且已知水果的种类数和每种水果的数目。
你的任务是设计出合并的次序方案,使小明耗费的体力最少,并输出这个最小的体力耗费值。
例如有 3 种水果,数目依次为 1,2,9。可以先将 1,2 堆合并,新堆数目为3,耗费体力为 3。
然后将新堆与原先的第三堆合并得到新的堆,耗费体力为 12。
所以小明总共耗费体力=3+12=15,可以证明 15 为最小的体力耗费值。

输入

每组数据输入包括两行,第一行是一个整数 n(1<=n<=10000),表示水果的种类数。
第二行包含 n 个整数,用空格分隔,第 i 个整数(1<=ai<=1000)是第 i 种水果的数目。

输出

对于每组输入,输出一个整数并换行,这个值也就是最小的体力耗费值。
输入数据保证这个值小于 2^31。

样例输入 Copy
3
9 1 2
0
样例输出 Copy
15
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <list>
#include <deque>
#include <bitset>
#include <unordered_set> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const int N = 3e3+10;
const int M = 1e9+7;
const int inf = 0x3fffffff;
const int P = 13331;
void solve(){
    int n;
    while(cin>>n&&n){
        vector<int> a(1001,0);
        queue<int> q,qq;
        for(int i=1;i<=n;i++){
            int x;
            cin>>x;
            a[x]++;
        }
        for(int i=1;i<=1000;i++){
            while(a[i]>0){
                a[i]--;
                q.push(i);
            }
        }
        int sum=0;
        int x,y;
        for(int i=1;i<n;i++){
            if((q.front()<qq.front()&&!q.empty())||qq.empty()){
                x=q.front();
                q.pop();
            }
            else {
                x=qq.front();
                qq.pop();
            }
            if((q.front()<qq.front()&&!q.empty())||qq.empty()) {
                y=q.front();
                q.pop();
            }
            else {
                y=qq.front();
                qq.pop();
            }
            sum+=x+y;
            qq.push(x+y);
        }
        cout<<sum<<"\n";
    }
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    //int T;cin>>T;for(int i=1;i<=T;i++)
    solve();
    return 0;
}

H: 打牌

牌只有1到9,手里拿着已经排好序的牌a,对方出牌b,用程序判断手中牌是否能够压过对方出牌。  
规则:出牌牌型有5种。
[1] 一张 如4 则5...9可压过 
[2] 两张 如44 则55,66,77,...,99可压过 
[3] 三张 如444 规则如[2] 
[4] 四张 如4444 规则如[2] 
[5] 五张 牌型只有12345 23456 34567 45678 56789五个,后面的比前面的均大。

输入

输入有多组数据。
每组输入两个字符串(字符串大小不超过100)a,b。
a字符串代表手中牌,b字符串代表出的牌。

输出

压过输出YES 否则NO。

样例输入 Copy
12233445566677
33
样例输出 Copy
YES
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e4 + 5;
int c[15];
void solve(){
    string a,b;
    while(cin>>a>>b){
        if(a.size()<b.size()){
            cout<<"NO\n";
        }
        else{
            memset(c,0,sizeof c);
            for(int i=0;i<a.size();i++){
                c[a[i]-'0']++;
            }
            if(b.size()==5){
                if(b[0]=='5'){
                    cout<<"NO\n";
                }
                else{
                    bool t=false;
                    for(int i=b[0]-'0'+1;i<6;i++){
                        if(c[i]&&c[i+1]&&c[i+2]&&c[i+3]&&c[i+4]){
                            t=true;
                            cout<<"YES\n";
                            break;
                        }
                    }
                    if(!t){
                        cout<<"NO\n";
                    }
                }
            }
            else{
                if(b[0]=='9'){
                    cout<<"NO\n";
                }
                else{
                    bool t=false;
                    for(int i=b[0]-'0'+1;i<10;i++){
                        if(c[i]>=b.size()){
                            t=true;
                            cout<<"YES\n";
                            break;
                        }
                    }
                    if(!t){
                        cout<<"NO\n";
                    }
                }
            }
        }
    }
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    solve();
    return 0;
}

 I: 狮子座的失眠

狮子座自从上次几乎素数问题没有解决后,开始了失眠之夜,于是他开始了念数字游戏,不过他念的方式很奇妙,他念的是每个数字的拼音,例如:-600 他念的是“fu liu ling ling”。

输入

输入一个整数,保证最多只有4位数,输出每个数字对应的拼音。当整数为负数时,先输出fu字。

输出

在一行中输出这个整数对应的拼音,每个数字的拼音之间用空格分开,行末没有最后的空格。如 yi er san si。

样例输入 Copy
-600
样例输出 Copy
fu liu ling ling

#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <algorithm>
#include <cstring>
#include <queue>
#include <stack>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int N = 2e4 + 5;
char c[10][10]={"ling","yi","er","san","si","wu","liu","qi","ba","jiu"};
void solve(){
    int n,a[20],i=1;
    cin>>n;
    if(n<0)
    {
        cout<<"fu"<<" ";
        n=-n;
    }
    a[0]=n%10;
    while(n/10>0)
    {
        n/=10;
        a[i]=n%10;
        i++;
    }
    for(int j=i-1;j>0;j--)
        cout<<c[a[j]]<<" ";
    cout<<c[a[0]]<<"\n";
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    solve();
    return 0;
}

J: 狮子座的简单统计题

编写程序统计每种不同的个位数字出现的次数。例如:给定 N=100311,则有 2 个 0,3 个 1,和 1 个 3。

输入

每个输入包含 1 个测试用例,即一个不超过 1000 位的正整数 N。

输出

对 N 中每一种不同的个位数字,以 D:M 的格式在一行中输出该位数字 D 及其在 N 中出现的次数 M。要求按 D 的升序输出。

样例输入 Copy
100311
样例输出 Copy
0:2
1:3
3:1
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <algorithm>
#include <cstring>
#include <queue>
#include <stack>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int N = 2e4 + 5;
void solve(){
     char n;
    int a[10]={0};
    while(cin>>n)
        a[n-'0']++;
    for(int i=0;i<10;i++)
        if(a[i]!=0)
            cout<<i<<":"<<a[i]<<"\n";
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    solve();
    return 0;
}

 K: 狮子座的复杂统计题

狮子座很快就把简单统计题ac了,现在他遇到了一个复杂的统计题。
有一组数据,你需要编程来求出次数出现最多的数字,保证输入是从小到大排序好了的。
如果有两个元素值出现的次数相同,即并列第一,那么只打印比较小的那个值。

输入

第一行输入一个整数 N ,N<=20 ,接下来有N个数字,保证从小到大排序,保证都在 int 范围内。

输出

输出只有一行,即出现次数最多的那个元素值。如果次数相同,输出较小的那个值。

样例输入 Copy
5
100
150
150
200
250
样例输出 Copy
150
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <algorithm>
#include <cstring>
#include <queue>
#include <stack>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int N = 2e4 + 5;
void solve(){
    int n,a[20],s=1,x,j=0;
    cin>>n;
    for(int i=0;i<n;i++)
        cin>>a[i];
    for(int i=1;i<n;i++)
    {
        if(a[i]==a[i-1])
            s++;
        else
        {
            if(s>j)
            {
                x=a[i-1];
                j=s;
            }
            s=1;
        }
    }
    cout<<x<<"\n";
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    solve();
    return 0;
}

 L: 狮子座的水题

狮子座最近在OJ做了一道最小公倍数的题,ac之后特别有成就感,还发现了gcd函数,于是他觉得最小公倍数问题都是水题了。突然,一个叫“欧几里得”的dalao重新排了一道关于最小公倍数的题,题目如下:求出n个数的最小公倍数。 于是,狮子座顿时方了,他只会求两个数的最小公倍数。此时向你求助,请帮助他完成这道题。

输入

输入包含多个测试实例,每个测试实例的开始是一个正整数n,然后是n个正整数。保证都处于int范围内。

输出

为每组测试数据输出它们的最小公倍数,每个测试实例的输出占一行。

样例输入 Copy
2 4 6
样例输出 Copy
12
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <algorithm>
#include <cstring>
#include <queue>
#include <stack>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int N = 2e4 + 5;
int gcd(int a,int b) {
    return b>0 ? gcd(b,a%b):a;
}
void solve(){
    int n,a,i,x;
    while(cin>>n)
    {
        cin>>a;
        i=n-1;
        for(int j=0;j<i;j++)
        {
            cin>>x;
            a=a*x/gcd(a,x);
        }
        cout<<a<<"\n";
    }
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    solve();
    return 0;
}

 M: 幸运数

众所周知,不管是人还是熊都需要人品。于是乎,为了给自己找一个幸运数字,Mavis 学习了人类的阿拉伯数字,并不知从哪儿弄来了一串序列和一个 S,Mavis 说:“长度最短且和大于等于 S 的连续子段的长度, 就是俺的幸运数字”!

   但是 Mavis 只会喊口号,不会解决问题,所以这个问题就交给你了。

输入

输入文件共三行。 

第一行输入仅一个正整数 n,意义如题所述。( n ≤ 4000000, ai ≤ 10^9) 

第二行输入 n 个正整数 ai,表示序列中的元素。 

第三行输入仅一个正整数 S,意义如题所述。 

每两个输入的数之间都用一个空格隔开。 

输出

输出文件仅一行一个整数,表示幸运数。

样例输入 Copy
8
4 12 10 18 17 10 17 17
40
样例输出 Copy
3
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <algorithm>
#include <cstring>
#include <queue>
#include <stack>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int N = 4e6 + 5;
ll a[N];
void solve(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    ll s;
    cin>>s;
    ll i=1,j=1;
    ll sum=a[1];
    ll ss=1e17;
    while(j<=n){
        if(sum>=s){
            ss=min(ss,j-i+1);
            sum-=a[i];
            i++;
        }
        else{
            j++;
            sum+=a[j];
        }
    }
    if(ss==1e17){
        ss=0;
    }
    cout<<ss<<"\n";
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    solve();
    return 0;
}

 N: 跳跃版图

有一个 n×n 的格子,每个格子中有一个非负整数。你的目标是从左上角跳到右下角,每步只能向右或向下跳。格子中的数代表从该格开始跳跃的前进步数,如果某次跳跃会跃出格子 界限则该跳跃是禁止的。注意 0 是一个绝对终点,因为从这里无法再移动。

你的任务是统计有多少种合法路径。上图 1 中共有 3 种路径,分别表示在图 2 中。

输入

第一行,一个整数 n(3 ≤ n ≤ 100)。

接下来 n 行 n 列,表示格子中的数,所有数的范围在[0,9]中,两个数之间用一个空格隔开。 

输出

第一行,从左上角到右下角的合法路径数目。 

样例输入 Copy
4
2 3 3 1
1 2 1 3
1 2 3 1
3 1 1 0 
样例输出 Copy
3
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <list>
#include <deque>
#include <bitset>
#include <unordered_set> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const int N = 3e3+10;
const int M = 1e9+7;
const int inf = 0x3fffffff;
const int P = 13331;
string fun(string a,string b){
    string s;
    int t=0;
    int i=a.size()-1,j=b.size()-1;
    while(i>=0||j>=0||t){
        int sum=t;
        if(i>=0){
            sum+=a[i--]-'0';
        }
        if(j>=0){
            sum+=b[j--]-'0';
        }
        t=sum/10;
        s.push_back((sum%10)+'0');
    }
    reverse(s.begin(), s.end());
    return s;
}
void solve(){
    int n;
    cin>>n;
    vector<vector<int>> a(n,vector<int>(n));
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            cin>>a[i][j];
        }
    }
    vector<vector<string>> dp(n,vector<string>(n,"0"));
    dp[0][0]="1";
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(dp[i][j]=="0"||a[i][j]==0){
                continue;
            }
            int x=j+a[i][j];
            if(x<n){
                dp[i][x]=fun(dp[i][x],dp[i][j]);
            }
            int y=i+a[i][j];
            if(y<n){
                dp[y][j]=fun(dp[y][j],dp[i][j]);
            }
        }
    }
    cout<<dp[n-1][n-1]<<"\n";
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    //int T;cin>>T;for(int i=1;i<=T;i++)
    solve();
    return 0;
}

O: 耶路撒冷战役

第二次十字军东征末期,由阿拉伯领袖萨拉丁率领的阿拉伯联军兵临圣城耶路撒冷。在城内驻扎的圣殿骑士团被歼灭之后,阿拉伯大军兵临城下。 

来到山岗上,萨拉丁极目远眺,见两小儿辩日, 发现自己的军队排成了一个 NM 大小的方阵。作为一个的军事家,这种阵型是他非常抵触的。于是他打算将他的军队分割成1*1大小的小队。 

然而拆分整编的军队是很费时间的一件事,对于行与行之间的每一条横线,列与列之间的每一条竖线,都有一个耗费时间的值(可以相同)。更加麻烦的是,拆分后的军队都是独立的,两个独立的部分不能拼接在一起拆分(比如一个显示器被拆成了两半,想把它拆成四份则需要对于已有的两份分别再拆一次) 。 

现在萨拉丁知道每一条横线和每一条竖线耗费时间的值,但是他很忙,所以不能处理出将NM的方阵拆成1*1的小队的总消耗时间的最小值,于是他转向你帮忙。

输入

第一行包含两个数N与M,分别表示行和列的数量。 

接下来N-1行,表示每一条横线的耗费时间值。 

接下来M-1行,表示每一条竖线的耗费时间值。
1 <= N , M <= 2000

输出

一个数表示总耗费时间的最小值。 

样例输入 Copy
2 2
3
3
样例输出 Copy
9
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <list>
#include <deque>
#include <bitset>
#include <unordered_set> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const int N = 3e3+10;
const int M = 1e9+7;
const int inf = 0x3fffffff;
const int P = 13331;
void solve(){
    int n,m;
    cin>>n>>m;
    vector<int> a(n-1),b(m-1);
    for(int i=0;i<n-1;i++){
        cin>>a[i];
    }
    for(int i=0;i<m-1;i++){
        cin>>b[i];
    }
    sort(a.rbegin(),a.rend());
    sort(b.rbegin(),b.rend());
    ll s=0;
    int i=0,j=0;
    int x=0,y=0;
    while(i<a.size()||j<b.size()){
        if(i<a.size()&&(j>=b.size()||a[i]>=b[j])){
            s+=(ll)a[i]*(y+1);
            x++;
            i++;
        } 
        else{
            s+=(ll)b[j]*(x+1);
            y++;
            j++;
        }
    }
    cout<<s<<"\n";
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    //int T;cin>>T;for(int i=1;i<=T;i++)
    solve();
    return 0;
}

P: Fy's dota2

Fy 觉得自己玩 cf,lol这种高端游戏已经够厉害了,于是他决定去玩dota2。结果 fy 的鼠标右键坏了,所以他就等到 2500 买了把闪烁匕首,用跳刀前进,准备去送泉水。但是 fy 一次最多前进 k 的距离,泉水离 fy 现在的距离是 n。

Fy 想知道他到泉水的方案数。

输入

第一行 2 个整数:k,n 
1<=n<=2^31-1,1<=k<=10 

输出

一行 1 个整数:代表答案对 7777777 取膜的结果 

样例输入 Copy
2 4
样例输出 Copy
5
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <list>
#include <deque>
#include <bitset>
#include <unordered_set>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const int N = 3e3+10;
const int inf = 0x3fffffff;
const int P = 13331;
const int MOD = 7777777;
vector<vector<ll>> mul(vector<vector<ll>> a,vector<vector<ll>> b){
    int k=a.size();
    vector<vector<ll>> s(k,vector<ll>(k,0));
    for(int i=0;i<k;i++){
        for(int j=0;j<k;j++){
            for(int z=0;z<k;z++){
                s[i][j]=(s[i][j]+a[i][z]*b[z][j])%MOD;
            }
        }
    }
    return s;
}
vector<vector<ll>> m_qpow(vector<vector<ll>> a,int t){
    int k=a.size();
    vector<vector<ll>> s(k,vector<ll>(k,0));
    for(int i=0;i<k;i++){
        s[i][i]=1;
    }
    while(t){
        if(t&1){
            s=mul(s,a);
        }
        a=mul(a,a);
        t/=2;
    }
    return s;
}
vector<ll> fun(vector<vector<ll>> a,vector<ll> ss){
    int k=a.size();
    vector<ll> s(k,0);
    for(int i=0;i<k;i++){
        for(int j=0;j<k;j++){
            s[i]=(s[i]+a[i][j]*ss[j])%MOD;
        }
    }
    return s;
}
void solve(){
    int k,n;
    cin>>k>>n;
    vector<ll> dp(k);
    dp[0]=1;
    for(int i=1;i<k;i++){
        dp[i]=0;
        for(int j=0;j<i;j++){
            dp[i]=(dp[i]+dp[j])%MOD;
        }
    }
    if(n<k){
        cout<<dp[n]%MOD<<"\n";
        return;
    }
    vector<vector<ll>> m(k,vector<ll>(k,0));
    for(int i=0;i<k;i++){
        m[0][i]=1;
    }
    for(int i=1;i<k;i++){
        m[i][i-1]=1;
    }
    int t=n-k+1;
    vector<vector<ll>> s=m_qpow(m,t);
    vector<ll> ss(k);
    for(int i=0;i<k;i++){
        ss[i]=dp[k-1-i];
    }
    vector<ll> ans=fun(s,ss);
    cout<<ans[0]%MOD<<"\n";
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    //int T;cin>>T;for(int i=1;i<=T;i++)
    solve();
    return 0;
}

Q: 河畔军训

河畔镇是一个景色秀丽,气候宜人的度假胜地,每天都会有很多的游客来这里游玩。但奇怪的是这里总会出现一些潜伏者。果不其然,通过保卫者的跟踪,发现在河畔镇的地下隐藏着Blitz的秘密武器实验室。最危险的地方也是最安全的地方,这里人多,所以只能采用狙击作战,一场“无声无息“的战斗即刻打响。 
每到周末小z,小y便开始在河畔军训小h(当然有时也会被反军训)。
不过他们军训采用刀战(即相遇时才可军训)
每当小z,小y,小h三人在河畔整相遇时,小z和小y便可军训小h
由于小h有兔耳朵buff加成,小h每秒最多可以移动3步,且可以选择上/下/左/右/左上/左下/右上/右下8个方向移动
小z,小y每秒均只能移动1步,只能上/下/左/右4个方向移动。
当然,三人均可选择保持原地不动。
三人移动始终在地图范围内。
下面,给你河畔的地图以及小z,小y,小h的初始坐标。
请你求出最快军训小h的时间(即3人相遇的最短时间),如果无法军训小h则输出“lack of junxun”

输入

多组数据
每组数据第一行两个整数N,M(1<=N,M<=1000)代表河畔地图的行和列
接下来是N*M大小的地图
其中“z”,“y”,“h”分别代表小z,小y,小h的初始坐标
“#”代表障碍物,“.”表示可以正常通过的位置

输出

对于每组数据
如果能军训小h,则输出最快军训小h所需的时间
否则,输出“lack of junxun”

样例输入 Copy
2 4
z..h
#y#.
2 3
z#y
#h.
样例输出 Copy
1
lack of junxun

#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <list>
#include <deque>
#include <bitset>
#include <unordered_set>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const int N = 3e3+10;
const int inf = 0x3fffffff;
const int P = 13331;
const int MOD = 7777777;
int d4[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int d8[8][2]={{-1,0},{1,0},{0,-1},{0,1},{-1,-1},{-1,1},{1,-1},{1,1}};
int n,m;
struct S{
    int x,y;
};
vector<vector<int>> bfs1(vector<string> a,int x,int y){
    vector<vector<int>> dis(n,vector<int>(m,inf));
    queue<S> q;
    dis[x][y]=0;
    q.push({x,y});
    while(!q.empty()){
        auto t=q.front();
        q.pop();
        for(int i=0;i<4;i++){
            int nx=t.x+d4[i][0];
            int ny=t.y+d4[i][1];
            if(nx>=0&&nx<n&&ny>=0&&ny<m&&a[nx][ny]!='#'&&dis[nx][ny]==inf){
                dis[nx][ny]=dis[t.x][t.y]+1;
                q.push({nx,ny});
            }
        }
    }
    return dis;
}
vector<vector<int>> bfs2(vector<string> a,int x,int y){
    vector<vector<int>> dis(n,vector<int>(m,inf));
    queue<S> q;
    dis[x][y]=0;
    q.push({x,y});
    while(!q.empty()){
        auto t=q.front();
        q.pop();
        int xx=t.x,yy=t.y;
        int s=dis[xx][yy];
        for(int i=0;i<8;i++){
            int nx=xx+d8[i][0];
            int ny=yy+d8[i][1];
            if(nx>=0&&nx<n&&ny>=0&&ny<m&&a[nx][ny]!='#'){
                if(dis[nx][ny]>s+1) {
                    dis[nx][ny]=s+1;
                    q.push({nx,ny});
                }
            }
        }
        for(int i1=0;i1<8;i1++){
            int nx1=xx+d8[i1][0];
            int ny1=yy+d8[i1][1];
            if(nx1<0||nx1>=n||ny1<0||ny1>=m||a[nx1][ny1]=='#'){
                continue;
            }
            for(int i2=0;i2<8;i2++){
                int nx2=nx1+d8[i2][0];
                int ny2=ny1+d8[i2][1];
                if(nx2<0||nx2>=n||ny2<0||ny2>=m||a[nx2][ny2]=='#'){
                    continue;
                }
                if(dis[nx2][ny2]>s+1) {
                    dis[nx2][ny2]=s+1;
                    q.push({nx2,ny2});
                }
            }
        }
        for(int i1=0;i1<8;i1++){
            int nx1=xx+d8[i1][0];
            int ny1=yy+d8[i1][1];
            if(nx1<0||nx1>=n||ny1<0||ny1>=m||a[nx1][ny1]=='#'){
                continue;
            }
            for(int i2=0;i2<8;i2++){
                int nx2=nx1+d8[i2][0];
                int ny2=ny1+d8[i2][1];
                if(nx2<0||nx2>=n||ny2<0||ny2>=m||a[nx2][ny2]=='#'){
                    continue;
                }
                for(int i3=0;i3<8;i3++){
                    int nx3=nx2+d8[i3][0];
                    int ny3=ny2+d8[i3][1];
                    if(nx3>=0&&nx3<n&&ny3>=0&&ny3<m&&a[nx3][ny3]!='#'){
                        if(dis[nx3][ny3]>s+1) {
                            dis[nx3][ny3]=s+1;
                            q.push({nx3,ny3});
                        }
                    }
                }
            }
        }
    }
    return dis;
}
void solve(){
    while(cin>>n>>m){
        vector<string> a(n);
        int zx,zy;
        int yx,yy;
        int hx,hy;
        for(int i=0;i<n;i++){
            cin>>a[i];
            for(int j=0;j<m;j++){
                if(a[i][j]=='z'){
                    zx=i;
                    zy=j;
                    a[i][j]='.';
                }
                else if(a[i][j]=='y'){
                    yx=i;
                    yy=j;
                    a[i][j]='.';
                } 
                else if(a[i][j]=='h'){
                    hx=i;
                    hy=j;
                    a[i][j]='.';
                }
            }
        }
        vector<vector<int>> disz=bfs1(a,zx,zy);
        vector<vector<int>> disy=bfs1(a,yx,yy);
        vector<vector<int>> dish=bfs2(a,hx,hy);
        int mi=inf;
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(disz[i][j]==inf||disy[i][j]==inf||dish[i][j]==inf){
                    continue;
                }
                int mm=max(disz[i][j],max(disy[i][j], dish[i][j]));
                mi=min(mi,mm);
            }
        }
        if(mi!=inf){
            cout<<mi<<"\n";
        } 
        else{
            cout<<"lack of junxun\n";
        }
    }
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    //int T;cin>>T;for(int i=1;i<=T;i++)
    solve();
    return 0;
}

R: 小B旅游

小B在一个有N个城市M条道路的国家,每条道路连接的城市可以互相到达且每条道路小B都要花1步去走过它。现在他在1号城市,问他走P步最多能走多少个不同的城市? 
输入
输入格式:第1行,三个正整数N、M、P,意义如题:接下来M行,每行两个整数U、V,表示存在一条连接U、V的无向边。
输出
输出格式:1行,一个整数,表示从1号城市出发走P步的所有情况,共能经过多少个不同的城市。 
样例输入 Copy
4 4 2
1 2
1 3
2 3
3 4
样例输出 Copy

4

提示

数据规模:

 1<=N<=100000,1<=M<=5000000,1<=P<=10000

#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <list>
#include <deque>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const int N = 1e3+5;
const int M = 1e9+7;
const int inf = 0x3fffffff;
const int P = 13331;
int n,m,p;
struct S{
    int x,y;
};
void solve(){
    cin>>n>>m>>p;
    vector<vector<int>> a(n+1);
    while(m--){
        int u,v;
        cin>>u>>v;
        a[u].push_back(v);
        a[v].push_back(u);
    }
    vector<bool> b(n+1,false);
    set<int> st;
    queue<S> q;
    q.push({1,0});
    b[1]=true;
    st.insert(1);
    while(!q.empty()){
        auto t=q.front();
        q.pop();
        if(t.y>p){
            continue;
        }
        st.insert(t.x);
        for(auto xx:a[t.x]){
            if(!b[xx]){
                b[xx]=true;
                q.push({xx,t.y+1});
            }
        }
    }
    cout<<st.size()<<"\n";
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    //int T;cin>>T;for(int i=1;i<=T;i++)
    solve();
    return 0;
}

 S: 括号匹配

括号主要有:大括号“{ }”、中括号“[ ]”、小括号“( )”。给定一个只包含左右括号的合法括号序列(序列长度2<=n<=10000),按右括号从左到右的顺序输出每一对配对的括号出现的位置(括号序列以0开始编号) 

输入

输入格式:仅1行,表一个合法的括号序列 

输出

输出格式:设括号序列有n个右括号,每行两个整数l、r,表示配对的括号左括号出现在第l位,右括号出现在第r位。 

样例输入 Copy
{()[()()]}()
样例输出 Copy
1 2
4 5
6 7
3 8
0 9
10 11
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e4 + 5;
void solve(){
    string s;
    cin>>s;
    stack<int> st;
    for(int i=0;i<s.size();i++){
        if(s[i]=='{'||s[i]=='['||s[i]=='('){
            st.push(i);
        }
        else if(s[i]=='}'){
            int l=st.top();
            st.pop();
            cout<<l<<" "<<i<<"\n";
        }
        else if(s[i]==']'){
            int l=st.top();
            st.pop();
            cout<<l<<" "<<i<<"\n";
        }
        else if(s[i]==')'){
            int l=st.top();
            st.pop();
            cout<<l<<" "<<i<<"\n";
        }
    }
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    solve();
    return 0;
}

 T: 正常血压

监护室每小时测量一次病人的血压,若收缩压在90-140之间并且舒张压在60-90之间(包含端点值)则称之为正常。
现给出某病人若干次测量的血压值,计算病人保持连续正常血压的最长小时数。

输入

单组输入,每组n+1行。
第一行为一个正整数n(n<100),其后有n行,每行2个正整数,分别为一次测量的收缩压和舒张压。 

输出

输出仅一行,表示血压连续正常的最长小时数。

样例输入 Copy
4
100 80
90 50
120 60
140 90
样例输出 Copy
2
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 + 5;
void solve(){
    int n;
    cin>>n;
    vector<pair<int,int>> p(n);
    for(int i=0;i<n;i++){
        cin>>p[i].first>>p[i].second;
    }
    int s=0;
    int m=0;
    for(int i=0;i<n;i++){
        if(p[i].first>=90&&p[i].first<=140&&p[i].second>=60&&p[i].second<=90){
            m++;
            s=max(s,m);
        } 
        else{
            m=0;
        }
    }
    cout<<s<<"\n";
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    solve();
    return 0;
}

 U: 三进制回文数

三进制回文数是指一个三进制数同时又是一个回文数,例如121、102201。
现在输入两个十进制正整数m和n,m<n,请编写一个程序统计在m和n之间(包括m和n)有多少个十进制正整数转换成三进制数之后可以得到三进制回文数。

输入

单组输入。
输入两个不超过1000的正整数m和n,m<n,二者之间用英文的空格隔开。

输出

输出在m和n之间(包括m和n)的十进制正整数转换成三进制数之后可以得到三进制回文数的个数。

样例输入 Copy
1 10
样例输出 Copy
5
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 + 5;
string fun(int n){
    string s="";
    while(n){
        char t=(n%3+'0');
        s+=t;
        n/=3;
    }
    reverse(s.begin(),s.end());
    return s;
}
bool fun1(string a){
    string b=a;
    reverse(a.begin(),a.end());
    if(a==b){
        return true;
    }
    return false;
}
void solve(){
    int m,n;
    cin>>m>>n;
    int s=0;
    for(int i=m;i<=n;i++){
        if(fun1(fun(i))){
            s++;
        }
    }
    cout<<s<<"\n";
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    solve();
    return 0;
}

 V: hy的战犯评级(Easy)

本题与战犯评级(Hard) 的唯一区别是n的范围。 

hy最近迷上了科幻小说《银河帝国》,想在银河系大显身手的他启动了《Stellaris》。 在遭到游戏中其他国家的无情羞辱后,开战!开战!一名p社战犯就这么诞生了... hy占领了m个星系,他想知道自己的势力如何,于是发明了战犯评级算法: 银河系是一个2n x 2n大小的矩阵,每个位置有一个星系。定义i级星区为左上角点横纵坐标均mod 2(i-1) = 1,大小 2i-1× 2i-1  的矩阵(如下图);特殊地,1级星区是一个星系。当一个i级星区内至少2个i-1级星区已 占领时,则认为该i级星区已占领 定义战犯等级为占领最大星区的等级,你能求出这个数值,以便在军事法庭上痛斥hy的战争罪 行吗?

输入

每个测试文件仅有一组测试数据。

第一行输入两个整数n,m(0<=n<=10,0<=m<=105)表示银河系是2n × 2n大小的矩阵,已占领m个星 系。

对于接下来m行,第i行输入两个整数xi和yi(1<=xi,yi<=2n),表示占领的第i个星系在银河系中的位 置。输入保证所有位置两两不同。 

输出

输出一行一个整数表示hy是几级战犯。

样例输入 Copy
2 6
1 1
1 2
2 2
2 3
2 4
4 4
样例输出 Copy
3
提示

由于占领了(1,1),(1,2),(2,2)三个星系,因此占领了以(1,1)为左上角的2级星区
 由于占领了(2,3),(2,4)两个星系,因此占领了以(1,3)为左上角的2级星区
 由于占领了以(1,1)和(1,3)为左上角的二级星区,因此占领了以(1,1)为左上角的3级星

#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <list>
#include <deque>
#include <bitset>
#include <unordered_set> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const int N = 3e3+10;
const int M = 1e9+7;
const int inf = 0x3fffffff;
const int P = 13331;
void solve(){
    int n,m;
    cin>>n>>m;
    vector<unordered_set<ll>> st(n+2);
    for(int i=0;i<m;i++){
        int x,y;
        cin>>x>>y;
        ll k=((ll)x<<16)|y;
        st[1].insert(k);
    } 
    if(n==0){
        if(m){
            cout<<"1\n"; 
        }
        else{
            cout<<"0\n";
        }
        return;
    }
    for(int i=2;i<=n+1;i++){
        int k=1<<(i-1);//2的i-1次方 
        int s=k>>1;
        int max=(1<<n)-k+1;//最大有效值 
        if(max<1){
            continue;
        } 
        unordered_set<ll> sst;
        for(int j=1;j<=max;j+=k){
            for(int z=1;z<=max;z+=k){
                int x1=j,y1=z;
                int x2=j,y2=z+s;
                int x3=j+s,y3=z;
                int x4=j+s,y4=z+s;
                int cnt=0;
                ll k1=((ll)x1<<16)|y1;
                if(st[i-1].count(k1)){
                    cnt++;
                }
                ll k2=((ll)x2<<16)|y2;
                if(st[i-1].count(k2)){
                    cnt++;
                }
                ll k3=((ll)x3<<16)|y3;
                if(st[i-1].count(k3)){
                    cnt++;
                }
                ll k4=((ll)x4<<16)|y4;
                if(st[i-1].count(k4)){
                    cnt++;
                }
                if(cnt>=2){
                    ll kk=((ll)j<<16)|z;
                    sst.insert(kk);
                } 
            }
        }
        st[i]=sst;
    }
    for(int i=n+1;i>=1;i--){
        if(!st[i].empty()){
            cout<<i<<"\n";
            return;
        }
    }
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    //int T;cin>>T;for(int i=1;i<=T;i++)
    solve();
    return 0;
}

W: hy的战犯评级(Hard)

本题与战犯评级(Easy) 的唯一区别是n的范围:在Easy版中,n=10。

hy最近迷上了科幻小说《银河帝国》,想在银河系大显身手的他启动了《Stellaris》。 在遭到游戏中其他国家的无情羞辱后,开战!开战!一名p社战犯就这么诞生了... hy占领了m个星系,他想知道自己的势力如何,于是发明了战犯评级算法: 银河系是一个2n x 2n大小的矩阵,每个位置有一个星系。定义i级星区为左上角点横纵坐标均mod 2(i-1) = 1,大小 2i-1× 2i-1  的矩阵(如下图);特殊地,1级星区是一个星系。当一个i级星区内至少2个i-1级星区已 占领时,则认为该i级星区已占领 定义战犯等级为占领最大星区的等级,你能求出这个数值,以便在军事法庭上痛斥hy的战争罪 行吗?

输入

每个测试文件仅有一组测试数据。

第一行输入两个整数n,m(0<=n<=60,0<=m<=105)表示银河系是2n × 2n大小的矩阵,已占领m个星 系。

对于接下来m行,第i行输入两个整数xi和yi(1<=xi,yi<=2n),表示占领的第i个星系在银河系中的位 置。输入保证所有位置两两不同。 

输出

输出一行一个整数表示hy是几级战犯。

样例输入 Copy
2 6
1 1
1 2
2 2
2 3
2 4
4 4
样例输出 Copy
3
提示

由于占领了(1,1),(1,2),(2,2)三个星系,因此占领了以(1,1)为左上角的2级星区
 由于占领了(2,3),(2,4)两个星系,因此占领了以(1,3)为左上角的2级星区
 由于占领了以(1,1)和(1,3)为左上角的二级星区,因此占领了以(1,1)为左上角的3级星

#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <list>
#include <deque>
#include <bitset>
#include <unordered_set>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const int N = 3e3+10;
const int M = 1e9+7;
const int inf = 0x3fffffff;
const int P = 13331;
//pair<T1, T2> 类型的哈希值
struct pair_hash {
    template<class T1, class T2>
    size_t operator() (const pair<T1, T2>& p) const {
        auto h1 = hash<T1>{}(p.first);
        auto h2 = hash<T2>{}(p.second);
        return h1 ^ (h2 << 1);
    }
};
void solve(){
    int n,m;
    cin>>n>>m;
    if(n==0){
        if(m){
            cout<<"1\n"; 
        }
        else{
            cout<<"0\n";
        }
        return;
    }
    unordered_set<pair<ull,ull>,pair_hash> st[62];
    for(int i=0;i<m;i++){
        ull x,y;
        cin>>x>>y;
        st[1].insert({x,y});
    }
    ull t=1LL<<n;
    for(int i=2;i<=n+1;i++){
        ull k=1LL<<(i-1);
        unordered_map<pair<ull,ull>,ull,pair_hash> mp;
        for(auto it:st[i-1]){
            ull x=it.first;
            ull y=it.second;
            ull xx=((x-1)/k)*k+1;
            ull yy=((y-1)/k)*k+1;
            if(++mp[{xx,yy}]==2){
                st[i].insert({xx, yy});
            }
        }
    }
    for(int i=n+1;i>=1;i--){
        if(!st[i].empty()){
            cout<<i<<"\n";
            return;
        }
    }
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    //int T;cin>>T;for(int i=1;i<=T;i++)
    solve();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值