Upc比赛--2

问题 A: 奇怪的道路

时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
从前,有一座网格城市,城市中每个房子占据一个正方形小格子的中心,每个正方形小格子的边长均为1。
这座城市道路的设计方式是这样的,首先,定义(a)图为一个基本图形,其阶为1,之后,将(a)图中每一个房子都用一个基本图形代替,得到(b)图,那么(b)图的阶即为2,再将(b)图中的每一个房子都用基本图形替代,得到阶为3的©图,以此类推,只要知道这座城市的阶n,就可以知道它的道路设计。
在这里插入图片描述

这种七拐八弯的道路设计使得这座城市之间的道路交通运输相当不便,于是该市的市长决定改造一下这座城市的道路,但在此之前他需要做一系列的评估,比如这座网格城市中,连接第i1行第j1列的房屋与第i2行第j2列的房屋之间(两座房屋可能相同)的道路有多长,由于这种道路设计太过奇怪,人力难以计算,于是这个任务就交给作为软件工程师的你了。
输入
每个测试点第一行有两个正整数n,T,表示城市的阶数和询问数。
接下来T行,每行4个正整数i1,j1,i2,j2,表示要查询的两个房屋的坐标。
输出
对每个询问输出一行相应的值表示答案。
样例输入 Copy
2 4
2 1 3 1
3 2 2 2
2 3 3 3
3 4 2 4
样例输出 Copy
13
11
1
3
提示
样例解释:
样例对应题目中的(b)图。
第一个询问问的是图中编号为2的房子与编号为15的房子的距离。
第二个询问问的是图中编号为14的房子与编号为3的房子的距离。
第三个询问问的是图中编号为8的房子与编号为9的房子的距离。
第四个询问问的是图中编号为10的房子与编号为7的房子的距离。

对于100%的数据,均有1≤n≤15,1≤i1,j1,i2,j2≤2n,1≤T≤10000。

思路: 回溯递归分治
从上图中我们可以找到一定规律,他分四块 ,为左上,左下,右上,右下。我们可以看出在整体上,这四个是 从左上到右上,再到右上 再到右下再到左下,也就是个顺时针,然后减一层就是单看一个分区,

  • 左上 他相当于上层的规律 发生对角线对称的规律,
  • 右上 它与上层 规律一样。+ 这层的平方
  • 左下 他是关于反对角线对称,+2倍的这层的平方
  • 右下 他与上层 归路也一样,+3倍的这层的平方
#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
using namespace std;
const int maxn=2e5+1010;
#define inf 0x3f3f3f3f
const int mod=998244353;
const int MOD=10007;

inline int read() {
	int x=0;
	bool t=false;
	char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}

priority_queue<ll , vector<ll> , greater<ll> > mn;//上  小根堆 		小到大 
priority_queue<ll , vector<ll> , less<ll> > mx;//下   	大根堆  	大到小
map<ll,ll>mp;

ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag,maxx,minn;
bool isprime[maxn];
ll a[maxn],b[maxn],c[maxn];
ll dis[maxn],vis[maxn];
ll dp[1010][1010];
string str,s;
ll qpow(ll a,ll b){
	ll sum=1;
	while(b){
		if(b&1) sum=sum*a;
		b>>=1;
		a=a*a;
	}
	return sum;
}

ll dfs(ll n,ll x,ll y){//分象限递归 
	if(n==0) return 1;
	ll mid=qpow(2,n-1);
	ll sum1=mid*mid;
	if(x<=mid&&y<=mid){
		return dfs(n-1,y,x);
	}else if(x<=mid&&y>mid) 
		return sum1+dfs(n-1,x,y-mid);
	else if(x>mid&&y>mid) return 2*sum1+dfs(n-1,x-mid,y-mid);
	else return 3*sum1+dfs(n-1,mid+1-y,2*mid+1-x);
}

int main(){
 	cin>>n>>m;
	for(int i=1;i<=m;i++) {
		ll x,y;
		cin>>x>>y>>l>>r;
		cout<<abs(dfs(n,l,r)-dfs(n,x,y))<<endl;
	}
	return 0;
}

问题 G: 艰难取舍

时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
由于hyf长得实在是太帅了,英俊潇洒,风流倜傥,人见人爱,花见花开,车见车载。
有一群MM排队看hyf。每个MM都有自己独特的风格,由于hyf有着一颗包容的心,所以,什么风格的MM他都喜欢……
但是,hyf有一个特别的要求,他不希望总是看到风格得差不多的MM,更加特别的是,如果两个MM风格完全一样,hyf不会有任何意见。
现在,hyf希望从去看他的MM中,去掉一些MM,从而使得相邻2个MM的风格值的差(绝对值)不为1。自然地,hyf希望去掉的MM越少越好。
输入
第一行一个整数N;
第2~N+1行N个整数,第i个为ci。表示第i个MM的风格值。
输出
一个数,表示最少要去掉的MM数。
样例输入 Copy
6
4
2
2
1
1
1
样例输出 Copy
2
提示
对于30%的数据,N≤20
对于70%的数据,N≤100,ci≤2000
对于100%的数据,N≤1000,0≤ci≤2000

思路 :DP:
去掉最少 留下最多。

代码:

#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
using namespace std;
const int maxn=2e5+1010;
#define inf 0x3f3f3f3f
const int mod=998244353;
const int MOD=10007;
 
inline int read() {
    int x=0;
    bool t=false;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
 
priority_queue<ll , vector<ll> , greater<ll> > mn;//上  小根堆        小到大 
priority_queue<ll , vector<ll> , less<ll> > mx;//下    大根堆     大到小
map<ll,ll>mp;
 
ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag,maxx,minn;
bool isprime[maxn];
ll prime[maxn],phi[maxn],pri[maxn]; 
ll a[maxn],b[maxn],c[maxn];
ll dis[maxn],vis[maxn];
ll dp[1010][1010];
string str,s;

int main(){
    cin>>n;
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    for(int i=1;i<=n;i++){
        dis[i]=1;
        for(int j=1;j<i;j++)
        if(abs(a[i]-a[j])!=1) dis[i]=max(dis[i],dis[j]+1);
     }
    sort(dis+1,dis+1+n);
    cout<<n-dis[n]<<endl;
    return 0;
}
 

问题 G: 最优分解问题

时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
设n是一个正整数。现在要求将n分解为若干个互不相同的自然数的和,且使这些自然数的乘积最大。
输入
第1行是正整数n。(n不超过50)
输出
计算出的最大乘积。
样例输入 Copy
10
样例输出 Copy
30

最大得坑,1,2 结果是0,




问题 F: 学佛和学水

时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
世界上存在2种人,学佛和学水……尽管他们考试都能得很高的分。
他们之间唯一的不同就是:学佛考试总是能独立完成,轻松AK,并且不屑于与学水为伍,他的佛光可以笼罩左右的同学,并且距离越远,佛光的作用越低。而学水考试的时候总会喜欢散发出与佛光能量相同的学水来吸引周围的同学一起作弊(合作)。
Fife所在的学校考试时,学生们所在的考场座位是排成一行,座位号L~R的顺序依次排列的。假设Fife的座位号为x,Bemy的座位号为y,则他们之间的距离为|x-y|。
考场上总有许多为学佛和学水,但更多的是一些普通学生。普通学生们总是会被周围的学佛和学水所左右迷惑。设每位普通学生离和他最近的学佛的距离为dis1, 和离他最近的学水的距离为dis2。如果dis1<dis2,则这位同学就会被佛光所笼罩,就有了与学佛相同的本领(能够独立完成,轻松AK)。如果dis1 >= dis2,则这位同学就会加入学水的队伍中,考试时就会一起合作(由于水的比热容较大,能够抵御强大的佛光,所以当dis1=dis2时,这位同学考试时也会和学水们合作)。
Fife作为远近闻名的大学佛,他容忍不了那些作弊(合作)的行为,所以他想让你告诉他,参加考试的人里面,有多少个人在考试的时候作弊(合作)。

输入
第一行三个数,n,l,r。n为学佛或学水的个数,l,r为所有考生的座位号。
接下来有n行,每行要么是‘NS x’,表示座位号为x的考生为学佛。
要么是‘S x’,表示座位号为x的考生为学水。

输出
一行一个整数n,表示考试作弊(合作)的人数。
样例输入 Copy
3 1 10
S 10
NS 4
S 1
样例输出 Copy
6
提示
样例解释
1,2,7,8,9,和10是作弊(合作)的人。

【数据规模】
对于40%的数据,1<=L<=R<=10,000,000。
对于100%的数据,N<=50,000,1<=L<=R<=1,000,000,000,L<=x<=R

思路: 就是做好标记,排序 ,然后比较上一个这一个 标记是否相同

#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
using namespace std;
const int maxn=2e5+1010;
#define inf 0x3f3f3f3f
const int mod=998244353;
const int MOD=10007;
 
inline int read() {
    int x=0;
    bool t=false;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
 
priority_queue<ll , vector<ll> , greater<ll> > mn;//上  小根堆        小到大 
priority_queue<ll , vector<ll> , less<ll> > mx;//下    大根堆     大到小
map<ll,ll>mp;
 
ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag,maxx,minn;
bool isprime[maxn];
ll a[maxn],b[maxn],c[maxn];
ll dis[maxn],vis[maxn];
ll dp[1010][1010];
string str,s;
struct node {
    ll id,sum; 
}q[maxn];
bool cmp(node a,node b){
    return a.sum<b.sum;
}
int main(){
    cin>>n>>l>>r;
    ll x;
    for(int i=1;i<=n;i++)
    {
        cin>>str>>x;
        if(str=="NS"){
            q[i].id=1;
            q[i].sum=x;
        }else if(str=="S"){
            cnt++;
            q[i].id=2;
            q[i].sum=x; 
        }
    }
    sort(q+1,q+1+n,cmp);
    flag=0,ans=0;
    for(int i=1;i<=n;i++){
        if(flag==0){
            if(q[i].id==2) sum+=q[i].sum-l;
         }else {
         if(q[i].id==2){
            if(flag==2){
                sum+=q[i].sum-q[i-1].sum-1;
             }else {
                ll y=q[i].sum-q[i-1].sum;
                sum+=y/2;
             }
         }else {
            if(flag==2) {
                ll y=q[i].sum-q[i-1].sum;
                sum+=y/2;
             }
         }
        }
        flag=q[i].id;
     }
     if(q[n].sum<r&&q[n].id==2) sum+=r-q[n].sum;
     cout<<sum+cnt<<endl;
    return 0;
}

问题 E: 人品指数

时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
队员们都到齐了,大家先入住宾馆,由于扬州是著名的旅游城市,宾馆房间很难预订,节目组预订的房间有高级的和普通的。怎样分配房间成了一个很棘手的问题,技术控李晨提出用“人品指数”来决定房间的好坏,根据往期的节目中的表现来计算人品,比如撕掉别人的名牌的人加10分,玩某个游戏得第一名加5分,第二名加3分等等。当然也可以减分,比如没有及时救助队友减10分,玩某个游戏超时减5分等等。不过,一次扣分和加分的数值不会超过100。
计算每个队员的人品指数时,每人一行。一开始的时候会给每个队员的人品指数设为100。比如李晨的信息为:lichen:100-3-5+1+2-2,则他的人品指数为:93。
到底谁能得到宾馆的最好房间呢?

输入
输入有若干行(不超过100行)。每行为一个队员的信息,其中首先是一个姓名(不超过20个字符的字符串,只含有小写字母和空格),后面是一个冒号,再后面为类似于数学的加减式(其中没有多余空格,保证合法)表示一个队员的人品加减分情况。
输出
输出人品指数最高的队员名单。如果有多个队员的人品指数一样高,请按姓名的字典顺序全部输出(一行一个姓名)。
样例输入 Copy
xiaoy:100-3-5+1+2-2
xiaox:100-10-20+1
xiaoz:100-50-50-1
样例输出 Copy
xiaoy
提示
对于100%的数据,队员的信息不超过100行。
思路:
结构体排序 : 有一点要注意 它不一定就输出一个 他说的全部输出 按字典序的顺序,所以最后要是与最大的相等也要输出,而且名字里有空格 所以要用getline或者gets 输入 之后就是计算分数,这样的话就是:遇到符号 进行前一次的符号运算,并清空这个数,把符号存下来,没遇到就加上这个数。
代码(可能不是正解,比较繁琐)

#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include <utility>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
using namespace std;
const int maxn=2e5+1010;
#define inf 0x3f3f3f3f
const int mod=998244353;
const int MOD=10007;
 
inline int read() {
    int x=0;
    bool t=false;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
 
priority_queue<ll , vector<ll> , greater<ll> > mn;//上  小根堆        小到大
priority_queue<ll , vector<ll> , less<ll> > mx;//下    大根堆     大到小
map<ll,ll>mp;
 
ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag,maxx,minn;
bool isprime[maxn];
ll a[maxn],b[maxn],c[maxn];
ll dis[maxn],vis[maxn];
ll dp[1010][1010];
string str,s;
struct node {
    string name;
    ll sum;
} q[maxn];
bool cmp(node a,node b) {
    if(a.sum!=b.sum) return a.sum>b.sum;
    else return a.name<b.name;
}
 
int main() {
    while(getline(cin,str)) {
        string name;
        for(int i=0; i<str.size(); i++) {
            if(str[i]==':') {
                flag=i;
                name=str.substr(0,i);
                break;
            }
        }
        q[++cnt].name=name;
        sum=0;
        char o='*';
        m=0;
    //  cout<<flag<<endl;
         
        for(int i=flag+1; i<str.size(); i++) {
            if(str[i]>='0'&&str[i]<='9') {
                m=m*10+str[i]-'0';
            } else if(str[i]=='-') {
                if(o=='*') {
                    sum=m;
                    m=0;
                    o='-';
                } else if(o=='-') {
                        sum=sum-m;
                        m=0;
                        o='-';
                    } else if(o=='+') {
                        sum=sum+m;
                        m=0;
                        o='-';
                    }
     
            }else if(str[i]=='+') {
                if(o=='*') {
                    sum=m;
                    m=0;
                } else {
                    if(o=='-') {
                        sum-=m;
                        m=0;
                         
                    } else if(o=='+') {
                        sum+=m;
                        m=0;
                    }
                }
                o='+';
            }
        //  cout<<m<<" "<<sum<<endl;
        }
        if(o=='-') {
            sum-=m;
            m=0;
        } else if(o=='+') {
            sum+=m;
            m=0;
        }
        q[cnt].sum=sum;
    }
    sort(q+1,q+1+cnt,cmp);
    ans=q[1].sum;
    for(int i=1;i<=cnt;i++)
        if(q[i].sum==ans)
        cout<<q[i].name<<endl;
        else break;
    return 0;
}

问题 F: 解密码

时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
跑男们都被关进了瘦西湖风景区中的不同地点,天才陈赤赤被关在了白塔中。为了打开门上的密码锁,必须按照规则变换锁上的数字:开始给定一个4位的质数a,每次改变质数的一位(改变后仍为质数),用最少的次数改变后得到b,若不可能,则次数为0。
“论吃饭我一个人可以拼他们六个!”
“你是猪吗?”
“嗝~~~”
……
陈赤赤啰嗦了大半天也没有半点头绪,眼看天就黑了,作为黑衣人的你实在看不下去了,扔了一张小纸条给他。

输入
输入共一行,包含两个整数a,b。
输出
输出共一行,包含一个整数,表示最少的步数。
样例输入 Copy
1033 8179
样例输出 Copy
6
提示
1033->1733->3733->3739->3779->8779->8179
其中1033,1733,3733,3739,3779,8779,8179均为质数。

思路:素数筛,bfs
首先 素数筛,一个数组判素,一个数组标记输入到达过(出现过)一个数组记录到达步数,一个数组模拟队列(就是从把步数降到最低),
这里需要特判一下 就是不能是数字成0000

#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include <utility>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
using namespace std;
const int maxn=2e5+1010;
#define inf 0x3f3f3f3f
const int mod=998244353;
const int MOD=10007;
 
inline int read() {
    int x=0;
    bool t=false;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
 
priority_queue<ll , vector<ll> , greater<ll> > mn;//上  小根堆        小到大 
priority_queue<ll , vector<ll> , less<ll> > mx;//下    大根堆     大到小
map<ll,ll>mp;
 
ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag,maxx,minn;
bool isprime[maxn];
ll a[maxn],b[maxn],c[maxn];
ll dis[maxn],vis[maxn];
ll dp[1010][1010];
ll ww,xx,yy,zz;
string str,s;
 
void prime(){
    a[1]=1;
    for(int i=2;i<=10000;i++)
    {
        if(a[i]==0) dis[++cnt]=i;
        for(int j=1;j<=cnt&&i*dis[j]<=10000;j++){
            a[i*dis[j]]=1;
            if(i%dis[j]==0) break;
        }
    }
}
 
ll dfs(){
    l=0,r=0;
    b[r++]=n;vis[n]=1; c[n]=0;//步数 
    while(l<r){
        flag=b[l++];
        if(flag==m) return c[flag];
        for(int i=1;i<=9999;i*=10){
            for(int j=0;j<=9;j++){
                if(i==1000&&j==0) continue;
                t=flag/(i*10)*i*10+i*j+flag%i;
                if(a[t]==0&&!vis[t]) {
                    vis[t]=1;
                    c[t]=c[flag]+1;
                    b[r++]=t;
                }
            }
        }       
    }
    return -1;
}
int main(){
    prime();
    cin>>n>>m;
    res=dfs();
    if(res!=-1) cout<<res<<endl;
    else cout<<-1<<endl;
    return 0;
}

问题 G: 迷宫

时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
晚上,跑男们来了节目的最后一站:江苏省扬州中学,完成最后一项比赛:撕名牌。撕名牌的地点是一个由n*n房间组成的正方形,每个房间里都有一个数字,表示从这个房间可以通过地道向右或向下穿过几个房间。从左上角开始,如果谁能安全到达右下角就算胜利。

这里4*4的方格中每一格表示进入这个房间时,队员可以向右或向下穿过的房间数。
郑恺是奔跑小王子,当他拿到这张地图时,脸都变绿了,速度再快,进了迷宫一样的房间也是没办法啊,还好参加JSOI2015夏令营的小伙伴都在,你能帮帮他算出从左上角可以到达右下角的路径数目吗?

输入
第一行为一个整数n,表示棋盘的大小。
以下有n行,每行有n个数字(数字与数字之间有一个空格隔开),表示在相应的格子内,棋子可以向右或向下跳跃的格子数。

输出
输出共一行,包含一个数,表示从左上角可以到达右下角的路径数目。
样例输入 Copy
4
2 3 3 1
1 2 1 3
1 2 3 1
3 1 1 0
样例输出 Copy
3
提示
对于100%的数据,1≤n≤100。
思路就是:dfs 这里要注意 棋盘中的数可能是0或者负数 所以当遇到0获或者否数时 就直接退出就行了;

#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include <utility>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
using namespace std;
const int maxn=2e5+1010;
#define inf 0x3f3f3f3f
const int mod=998244353;
const int MOD=10007;
 
inline int read() {
    int x=0;
    bool t=false;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
 
priority_queue<ll , vector<ll> , greater<ll> > mn;//上  小根堆        小到大 
priority_queue<ll , vector<ll> , less<ll> > mx;//下    大根堆     大到小
map<ll,ll>mp;
 
ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag,maxx,minn;
ll dp[201][201];
 
void dfs(ll x,ll y){
    if(x==n&&y==n) {
        sum++;
        return;
    }
    if(x>n||y>n) return;
    if(dp[x][y]<=0) return;
    //右
    dfs(x,y+dp[x][y]); 
    dfs(x+dp[x][y],y);
     
}
 
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
            cin>>dp[i][j];
     }
    dfs(1,1);
    cout<<sum<<endl;
    return 0;
}

问题 D: 迷宫

时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
迷宫的管理员们决定在新开始的季节里使用新的墙纸。出于这个目的他们需要一个程序来计算迷宫内墙壁的面积。这就是你即将要做的工作。
我们把这个迷宫用一个NN(3<=N<=33)的矩阵表示。一些矩阵单元包含一个“.”(这代表一个空的方块),另一些矩阵单元包含一个“#”(这代表一个用巨石砌成的石墙占据的方块)。全部方块的大小都为33平方米。

墙壁由迷宫的四周(除了作为迷宫出入口的左上角和右下角以外)以及那些标记为“#”的矩阵单元构成,除此之外没有其他的墙。在输入的矩阵里左上角和右下角永远是一个“.”。你的任务是计算迷宫里可见部分的墙壁的面积。换句话说,就是对迷宫的游客来说墙壁表面可见的部分。注意在两块相邻的石块之间没有空隙,即使两块石块在转角处相接触,我们都认为它们是相邻的。看看图示的例子:迷宫中可见的墙壁都用加粗的线条来描画。所有墙壁的高度都是三米。
输入
输入的第一行包含一个数字N。接下来的N行每行都包含有N个字符。每行描述了迷宫矩阵的一行。每行都只有“.”、“#”这两个字符并都以一个换行符结束。输入里没有任何的空格
输出
你的程序必须输出一个整数,即所需要的壁纸的准确面积。
样例输入 Copy
5

…##
…#…
…###

样例输出 Copy
198

思路:dfs bfs 就是深搜
如果上面是# 就是墙 如果不是就搜上面那个点,当然下,左,右也是这样,过程中要标记这个点是否经过过,经过过退出来,深搜两端是 因为它不一定是连通的。就要深搜 出入口。最后结果要减去 出口右下两块墙,和入口左上两块墙。最后乘以9.
代码:

#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include <utility>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
using namespace std;
const int maxn=2e5+1010;
#define inf 0x3f3f3f3f
const int mod=998244353;
const int MOD=10007;
 
inline int read() {
    int x=0;
    bool t=false;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
 
priority_queue<ll , vector<ll> , greater<ll> > mn;//上  小根堆        小到大 
priority_queue<ll , vector<ll> , less<ll> > mx;//下    大根堆     大到小
map<ll,ll>mp;
 
ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag,maxx,minn;
bool isprime[maxn];
ll a[maxn],b[maxn],c[maxn];
ll dis[maxn],vis[maxn];
ll dp[1010][1010];
char str[100][100],s;
 
void dfs(ll i,ll j){
    if(i<1||i>n||j<1||j>n) return;
    if(dp[i][j]==0) return;
        dp[i][j]=0;
     
    if(str[i+1][j]=='#'){
        sum++;
    }else {
        dfs(i+1,j);
    }
 
    if(str[i-1][j]=='#'){
        sum++;
    }else {
        dfs(i-1,j);
    }
     
    if(str[i][j+1]=='#'){
        sum++;
    }else {
        dfs(i,j+1);
    }
     
    if(str[i][j-1]=='#'){
        sum++;
    }else {
        dfs(i,j-1);
    }
     
}
int main(){
    cin>>n;
    for(int i=0;i<=n+2;i++)
        for(int j=0;j<=n+2;j++)
            str[i][j]='#';
     
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cin>>str[i][j];
            if(str[i][j]=='.')
                dp[i][j]=1;
        }
    }
     
    dfs(1,1);
    dfs(n,n);
    cout<<3*3*(sum-4)<<endl;
    return 0;
}

问题 E: MAX 的读书计划

时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
MAX 很喜欢读书,为了安排自己的读书计划,他会预先把要读的内容做好标记,A B 表示一个页段,即第 A 到 B 面,当然 A<B,若有两个页段 A-B,B-C,则可以直接记为 A-C,这样,他就可以一次看完,现在告诉你 n 个页段,请你帮他求出最长的一条页段,并输出这条页段的长度和组成它的页段个数。举个例子:
有 6 个页段:
2-7 1-3 3-12 12-20 7-10 4-50
那么连续的页段就有:
1-3,3-12,12-20 长度为 20-1+1=20 由 3 个页段组成
2-7,7-10 长度为 10-2+1=9 由 2 个页段组成
4-50 长度为 50-4+1=47 由 1 个页段组成
那么最长的一条就是第三个,所以结果为 47 1。
需要注意的是:如果有两条不一样的连续的页段长度同时为最大,那么取组成页段数多的一条.
例子: 1-5,5-10,1-10
输出: 10 2
输入
第一行为一个整数n,n<500;
第二行到第n+1行,每行两个整数A,B,记录一个页段的信息。0<=A<B<500
输出
输出一个整数,即最长的页段的长度和组成它的页段数。
样例输入 Copy
7
1 5
10 12
3 10
2 7
2 10
12 16
7 9
样例输出 Copy
15 3
提示
1-5 长度为5由1个页段组成
3-10,10-12,12-16 长度为14由3个页段组成
2-7,7-9 长度为8由2个页段组成
2-10,10-12,12-16 长度为15由3个页段组成

所以输出最长的页段的长度即15由3个页段组成

【数据规模】
对于30%的数据n<20,0<=A<B<500

思路:dfs 贪心
代码:

#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
using namespace std;
const int maxn=2e5+1010;
#define inf 0x3f3f3f3f
const int mod=1e9+7;
const int MOD=10007;
 
inline int read() {
    int x=0;
    bool t=false;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
 
priority_queue<ll , vector<ll> , greater<ll> > mn;//上  小根堆        小到大 
priority_queue<ll , vector<ll> , less<ll> > mx;//下    大根堆     大到小
map<ll,ll>mp;
 
ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag
,maxx,minn;
bool isprime[maxn];
ll a[maxn],b[maxn],c[maxn];
ll dis[maxn],vis[maxn];
ll dp[1010][1010];
string str,s;
 
struct king {
    ll id;
    string str;
}q[maxn];
bool cmp(king a,king b){
    if(a.id!=b.id) return a.id>b.id;
    else return a.str<b.str;
}
ll qpow(ll a,ll b){
    ll sum=1;
    while(b){
        if(b&1) sum=sum*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return sum;
}
 
 
int main(){
    cin>>n;
    for(int i=1;i<=n;i ++)
    {
        scanf("%lld%lld",&l,&r);
        dp[l][r]=r-l+1;
        maxx=max(maxx,r);
    }
    for(int i=0;i<=maxx;i++){
        for(int j=0;j<i;j++){
            if(dp[j][i]){
                if(dis[j]){
                    if(dis[i]<dis[j]+dp[j][i]){
                        dis[i]=dis[j]+dp[j][i]-1;
                        vis[i]=j;
                     }
                 }else {
                    dis[i]=max(dis[i],dp[j][i]);
                 }
             }
         }
     }
     for(int i=0;i<=maxx;i++)
     {
        if(dis[i]>minn)
            minn=dis[i];
     }
     sum=1;
     for(int i=0;i<=maxx;i++){
        if(dis[i]==minn){
            l=1,r=i;
            while(vis[r]!=0){
                l++;
                r=vis[r];
             }
            sum=max(sum,l);
         }
     }
     cout<<minn<<" "<<sum<<endl;
    return 0;
}

问题 F: 趾压板矩阵

时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
第二天早晨,跑男队员们来到了风景秀丽的扬州瘦西湖,刚下车他们全都尖叫起来,没错,就是他们最怕的“趾压板”:
一块超级大的趾压板被分成了n行n列,每个小格子上都有一个数字。游戏规则是:观察一段时间后,把所有的数字拿掉,分别抽取一个行号i和列号j,说出这个位置上原来的数字是多少,如果不能说出正确的值,就要接受处罚,光脚从左上角1沿着顺序从小到大走到这个数字所在位置。
在这里插入图片描述

“捡漏王”王祖蓝思考了一会,马上找到了其中的奥秘,你呢?

输入
输入共一行,包含三个整数n,i,j,每两个整数之间用空格隔开,分别表示矩阵大小、待求的数所在的行号和列号。

输出
输出共一行,包含一个整数,表示相应矩阵中第i行和第j列的数。
样例输入 Copy
7 4 3
样例输出 Copy
18
提示
对于50%的数据,1≤n≤100;
对于100%的数据,1≤n≤30,000,1≤i≤n,1≤j≤n。

思路:首先求出前缀和,就是每一斜线的最大值。
然后我们不难发现他们的坐标与他们的斜线的关系;就是坐标和-1(记为sum吧);
然后我是把它分成四种:
1,:当sum<=矩阵大小并且sum%2==0 我们可以知道他的最大值在右上,然后就这时我们求得的前缀和就用到了;(1,sum)-> (x,y) 只需是1->x 也就是让这个对应的前缀和减去(x-1);

2:当sum<=矩阵大小并且sum%2==1我么可以知道他的最大值在左下,
代码:

#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
using namespace std;
const int maxn=2e5+1010;
#define inf 0x3f3f3f3f
const int mod=1e9+7;
const int MOD=10007;
 
inline int read() {
    int x=0;
    bool t=false;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
 
priority_queue<ll , vector<ll> , greater<ll> > mn;//上  小根堆        小到大 
priority_queue<ll , vector<ll> , less<ll> > mx;//下    大根堆     大到小
map<ll,ll>mp;
 
ll n,m,l,r,p;
ll sum,ans,res,cnt,flag
,maxx,minn;
bool isprime[maxn];
ll a[maxn],b[maxn],t[maxn],c[maxn];
ll dis[maxn],vis[maxn];
ll dp[1010][1010];
string str,s;
 
struct king {
    ll id;
    string str;
}q[maxn];
bool cmp(king a,king b){
    if(a.id!=b.id) return a.id>b.id;
    else return a.str<b.str;
}
 
ll qpow(ll a,ll b){
    ll sum=1;
    while(b){
        if(b&1) sum=sum*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return sum;
}
 
int main(){
    cin>>n>>m>>p;
    for(int i=1;i<=n;i++)
        dis[i]=dis[i-1]+i;
    cnt=n;
    for(int i=n-1;i>=1;i--)
        dis[++cnt]=dis[cnt-1]+i;
/*  for(int i=1;i<=2*n-1;i++)
        cout<<dis[i]<<" ";
*/ 
    sum=m+p-1;
     
        //dis[sum] 最大  sum- 1
        if(sum<=n&&(sum%2==0))
        {
        for(int i=1;i<m;i++)
            dis[sum]--;
        cout<<dis[sum]<<endl;
        }else if(sum<=n&&sum%2==1){
            for(int i=sum;i>m;i--)
                dis[sum]--;
            cout<<dis[sum]<<endl;
        }
        else if(sum>n&&(sum%2==0))
        {
        //  cout<<dis[sum]<<endl;
        for(int i=sum-n+1;i<m;i++)
            dis[sum]--;
        cout<<dis[sum]<<endl;
        }else if(sum>n&&sum%2==1){
        //  cout<<dis[sum]<<endl;
            for(int i=n;i>m;i--)
                dis[sum]--;
            cout<<dis[sum]<<endl;
        }
     
     
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45911397/article/details/105934004
UPC