1.安卓图案解锁
题目描述
栗主席(lizi)是某xxxx大学的一个不得了的程序猿,然而没想到吧,他竟然有女盆友,我们假设为QAQ!!!
那天,QAQ问栗子:你的小米5s的图像解锁密码到底是多少?
栗子:嘛?我仔细想想...
QAQ:你仿佛在逗我...
...
栗子:我的图像解锁用过好多次密码,后来都是用指纹解锁,所以忘记密码辣。但是我记得可能是那几个密码
QAQ:那你务必告诉我...
栗子: ...
然后,栗子就写下了一堆可能的密码,安卓图案解锁中,数字对应的位置已经标出。
但是栗子当然不想把真正的密码告诉QAQ,所以给QAQ的一系列的密码中,甚至有一些密码,是不符合安卓图案解锁的规则的。
QAQ也知道栗子肯定不老实,给了很多错的密码,甚至不符合规则的密码,所以想请你来找出,哪些密码是不符合规则的。
安卓图案解锁的密码有这样的一些特点:
1.每个数字最多只会被使用一次。
2.如果想直接连接两个数字,但是线段中会经过另一个数字,当且仅有那个数字已经在之前就被使用过了,才会合法。(比如你想从1直接连接到9,那么要么是1->3->9,要么是3在之前已经被使用过了,然后才能直接从1->9)
输入描述:
多组输入
每组输入占一行,包含一串数字(1~9),长度不超过30
输出描述:
输出这个安卓图案解锁是否合法,如果合法输出"YES",反之输出"NO" (请参照样例输出,不要输出引号)
正确代码:
#include<iostream>
#include<string.h>
using namespace std;
int main() {
int a[9], b[9] = {1,2,1,3,0,3,1,2,1};
string c;
while (cin >> c) {
int pt = 1;
memset(a,0,sizeof(a));
for (int i = 0; i < c.size()-1; i++) {
int a1 = c[i] - '0';
int a2 = c[i + 1] - '0';
if (a1==a2){
pt = 0;
break;
}
if (a[a1 - 1]==1 || a[a2 - 1]==1) {
pt = 0;
break;
}
a[a1 - 1] = 1;
if(b[a1 - 1]==b[a2 - 1] && !a[(a1+a2)/2-1]) {
pt = 0;
break;
}
}
if (pt)
cout << "YES" << endl;
else cout << "NO" << endl;
}
}
总结:这道题体现的是数组模拟的思想,选对方法很关键。
把特殊情况分开来,1.一个数字连续连接,
2.连了早就连过的数字(判断未连过,则刷新数组)
3.跳过中间数字连两端
2.小红爱数数
正确代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int g[2*100000+5];
map<ll,int>m1;
map<ll,int>m2;
int main()
{
int n;ll sum=0;
cin>>n;
for(int i=1;i<=n;i++){
int a;
cin>>a;
if(m1.find(a)!=m1.end())
g[i]=g[m1.find(a)->second]+m2.find(a)->second*(i-m1.find(a)->second)+1;
if(m1.find(a)==m1.end()){
m1.insert(make_pair(a,i));
}
else {
m1.find(a)->second=i;
}
if(m2.find(a)==m2.end()){
m2.insert(make_pair(a,1));
}
else{
m2.find(a)->second++;
}
}
for(int i=1;i<=n;i++){
sum+=g[i];
}
cout<<sum<<endl;
}
总结:该题要找到没两个相同字符间的联系,从而计算总数:
使用 map m1记录上一个数字出现的位置(离散化后使用数组也可以),m2记录相同的数字有多少个, gi表示以 i为右端点时,所有满足条件的数对的距离总和是多少。转移:gi=g(k)+size*(i-k)+1, k为上一个相同数字。
3.奶牛发型(单调栈)
题目描述
一群身高不等的奶牛排成一排,向右看,每个奶牛只能看到身高小于自己的奶牛发型,问这些奶牛能够看到的发型总和是多少
自己写的代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
stack<ll>s;
ll n,sum=0;
cin>>n;
for(int i=0;i<n;i++){
ll c;
cin>>c;
while(!s.empty()&&s.top()<=c){
s.pop();
}
sum+=s.size();
s.push(c);
}
cout<<sum<<endl;
}
总结:首先弹出元素是因为它右边相邻牛比它高(看不到它的头发并且挡住了该牛的视线),“挡住”这个关键字很重要,这就是说该牛已经看不到后面的其他牛的头发啦,而思路一是按顺序比较身高,统计每头牛前面能看到它头发的牛数,既然该牛望不到后面,那么把它出栈对整个结果没有影响。
4.n皇后问题(假,模拟题)
皇后是国际象棋中实力最强的一种棋子,它可以攻击与它同行、同列、甚至斜向的其它棋子。
Komorebi最近刚刚了解到了n皇后问题,这个问题是这样的:
给你一个n×n的棋盘,有多少种放置方案可以让它们不能互相攻击。
然而这个问题对Komorebi还是太难了,也并不实用,现在他有一个n×n的空棋盘,并进行T次操作,他每次会试图在棋盘上的某一个格子放置一个皇后,如果这次放置不会使得有皇后互相攻击,那他就会将皇后放在这个位置,不然他就会放弃这次操作。
但因为棋盘太大了,每次他无法判断会不会使得有皇后互相攻击,你可以帮帮他吗?
自己写的代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
long n,t;
cin>>n>>t;
bool arr[n+1][n+1];
for(long i=0;i<n+1;i++)
for(int j=0;j<n+1;j++)
arr[i][j]=false;
for(long i=0;i<t;i++)
{
long x,y;
cin>>x>>y;
if(arr[x][y]==true)
{
cout<<"No"<<endl;
continue;
}
else
{
cout<<"Yes"<<endl;
for(long k=1;k<=n;k++)
{
arr[k][y]=true;//同一竖
arr[x][k]=true;//同一行
}
long t1=x,t2=y;
while(t1>=1&&t2>=1&&t1<=n&&t2<=n)
{
arr[t1++][t2--]=true;
}
t1=x,t2=y;
while(t1>=1&&t2>=1&&t1<=n&&t2<=n)
{
arr[t1--][t2--]=true;
}
t1=x,t2=y;
while(t1>=1&&t2>=1&&t1<=n&&t2<=n)
{
arr[t1--][t2++]=true;
}
t1=x,t2=y;
while(t1>=1&&t2>=1&&t1<=n&&t2<=n)
{
arr[t1++][t2++]=true;
}
}
}
}
正确代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
const int N=3*1e6+5;
int a[N],b[N],c[N],d[N];
int main()
{
int n,T;
scanf("%d%d",&n,&T);
memset(a,false,sizeof(a));
memset(b,false,sizeof(b));
memset(c,false,sizeof(c));
memset(d,false,sizeof(d));
for(int i=0;i<T;i++)
{
int x,y;
scanf("%d%d",&x,&y);
if(a[x]==true || b[y]==true || c[x+y]==true || d[x-y]==true)
{
printf("No\n");
continue;
}
else
{
printf("Yes\n");
a[x]=true;
b[y]=true;
c[x+y]=true;
d[x-y]=true;
}
}
}
总结:这道题套着N皇后的壳子,实际上只是一道模拟题。
在我自己写的代码中,桶排序完全没有必要,浪费时间也浪费空间,还容易造成内存冲突。
只需要标记行列,两斜(找跟坐标的关系),就行啦。