A - Prison Break
题意:
给定你一个
a
∗
b
a*b
a∗b的矩阵,把它看做一个监狱,然后问你最少打通多少面墙能使得一个人处于矩阵的任意一个方格内都可以逃脱。
思路:
找规律发现就是
a
∗
b
a * b
a∗b面。
#include <bits/stdc++.h>
using namespace std;
#define pb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
int main() {
int T;scanf("%d",&T);
while(T--) {
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",a * b);
}
return 0;
}
B - Restore Modulo
题意:
定义
n
,
m
(
m
≥
0
)
,
s
,
c
(
0
≤
c
<
m
)
n,m(m \geq 0),s,c(0\leq c <m)
n,m(m≥0),s,c(0≤c<m)四个数,然后这四个数可以生成的一个序列
a
a
a,生成规则如下:
a
1
=
s
m
o
d
m
a_1 = s\ mod \ m
a1=s mod m
a
i
+
1
=
(
a
i
+
c
)
m
o
d
m
a_{i+1} = (a_i +c )\ mod \ m
ai+1=(ai+c) mod m
这样得到一个长度为
n
n
n的序列a
然后问你给定一个序列
a
a
a,能否找到符合要求的
m
,
c
m,c
m,c使得这个序列可以被生成。有唯一解输出答案,无限多解输出0,无解输出-1。
思路:
这个B感觉比C还难,但是其实注意了题目的大小条件的话也还好。
首先
n
≤
2
n \leq 2
n≤2的话一定是无限多解的。
令
d
i
=
a
i
−
a
i
+
1
d_{i} = a_{i} - a _ {i+1}
di=ai−ai+1 ,如果
d
i
d_i
di都相等,那么也是无限多解。
首先
(
a
i
+
c
)
%
m
=
a
i
+
1
(a_i + c)\%m = a_{i+1}
(ai+c)%m=ai+1,即
a
i
−
a
i
+
1
=
k
m
+
c
a_i-a_{i+1} = km + c
ai−ai+1=km+c,但是别忘了我们序列的生成过程是不断取余
m
m
m的并且题目规定了合法的
c
c
c要小于
m
m
m,所以这里的
k
k
k只能取0 或 1。
即
a
i
−
a
i
+
1
=
m
+
c
a_i - a_{i+1} = m + c
ai−ai+1=m+c或者
a
i
−
a
i
+
1
=
c
a_i - a_{i+1} = c
ai−ai+1=c,可以看到对于一组确定的
m
m
m和
c
c
c我们
d
i
d_i
di序列只能最多存在两个不同的取值,大于的情况无解。
然后我们看 k m − c = d 1 km - c = d_1 km−c=d1, k m − c = d 2 km - c = d2 km−c=d2,我们知道了 0 ≤ c < m 0\leq c < m 0≤c<m,那么如果 d 1 / 2 < 0 d_{1/2} <0 d1/2<0,那么对应的一定有 k = 0 k = 0 k=0,假如 d 1 , d 2 d_1,d_2 d1,d2都小于0,而我们又知道 d 1 ≠ d 2 d_1 \neq d_2 d1=d2,此时 c c c无解。否则的话令 m m m = | d 1 d_1 d1 | + | d 2 d_2 d2 |, c = ∣ m i n ( d 1 , d 2 ) ∣ c = |min(d1,d2)| c=∣min(d1,d2)∣,这样求出来的m和c不一定是满足要求的还要再判断求出来的 m m m是否比序列 a a a的每个数都小,这样答案才合法,这样就可以两个d都大于0的情况判掉其实。
数据范围一定注意,解题的时候别忘记
#include <bits/stdc++.h>
using namespace std;
#define pb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 1e5 + 10;
ll a[N],d[N];
std::set<ll>ss;
int n;
//因为c要小于m a[i+1] = a[i] + c,而且a[i]也是小于m的,那么
//a[i] + c = a[i+1] + km,k = 1 或者 k = 0
int main() {
int T;scanf("%d",&T);
while(T--) {
ss.clear();
scanf("%d",&n);
ll ma = 0;
for(int i = 1;i <= n;i ++) {
scanf("%d",&a[i]);
ma = max(ma,a[i]);
}
if(n <= 2) {
printf("0\n");
continue;
}
for(int i = 1;i < n;i ++) {
d[i] = a[i] - a[i+1];
ss.insert(d[i]);
}
// cout << sz(ss) << '\n';
if(sz(ss) > 2) {//最多就是 c 和 c - m两个数
printf("-1\n");
}
else if(sz(ss) == 1) {
printf("0\n");
}
else {
if(*ss.begin() < 0LL && *ss.rbegin() < 0LL) {
printf("-1\n");
}
else {
ll c = abs(min(*ss.begin(),*ss.rbegin()));
ll m = abs(*ss.begin()) + abs(*ss.rbegin());
if(m <= ma) {
printf("-1\n");
}
else printf("%lld %lld\n",m,c);
}
}
}
return 0;
}
C - Basic Diplomacy
思路:
题目已经说明了
∑
k
≤
200000
\sum {k} \leq 200000
∑k≤200000,直接存个vector每天sort一下模拟过程就搞定。
#include <bits/stdc++.h>
using namespace std;
#define pb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 1e5 + 10;
const int M = 2e5 + 10;
//一个模拟
struct node {
int id;
node(){};
node(int _id) {
id = _id;
}
};
struct Node {
int id,k;
vector<node>v;
bool operator < (const Node& a) const {
return k < a.k;
}
}day[N];
int n,m,ans[N],cnt[N];
bool cmp(node a,node b) {
return cnt[a.id] < cnt[b.id];
}
int main() {
int T;scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&m);
for(int i = 0;i <= n;i ++) cnt[i] = 0;
for(int i = 0;i <= m;i ++) day[i].v.clear();
int ma = (m + 1) / 2;
int a;
for(int i = 1;i <= m;i ++) {
scanf("%d",&day[i].k);
for(int j = 1;j <= day[i].k;j ++) {
scanf("%d",&a);
day[i].v.pb(node(a));
}
day[i].id = i;
}
sort(day + 1,day + 1 + m);//把k值小的放在前面
int fg = 0;
for(int i = 1;i <= m;i ++) {
sort(day[i].v.begin(),day[i].v.end(),cmp);
node cur = day[i].v[0];
cnt[cur.id]++;
if(cnt[cur.id] > ma) {
fg = 1;
break;
}
ans[day[i].id] = cur.id;
}
if(fg) {
puts("NO");
}
else {
puts("YES");
for(int i = 1;i <= m;i ++) {
printf(i == m?"%d\n":"%d ",ans[i]);
}
}
}
return 0;
}
D - Playlist
题意:
给定你一个歌曲播放序列,每个歌曲都有对应的一个标志
a
i
a_i
ai,假如当前歌曲的
a
i
a_i
ai和播放列表中上一首歌曲
a
j
a_j
aj,二者
g
c
d
(
a
i
,
a
j
)
=
=
1
gcd(a_i,a_j) == 1
gcd(ai,aj)==1,则从播放列表中删去这首歌曲,并从下一首歌曲重新开始计数。
思路:
模拟一个链表的操作即可,不断维护当前节点和和它的
n
e
x
t
next
next指针,知道当前列表中已经没有连续的互质位置。
#include <bits/stdc++.h>
using namespace std;
#define pb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 2e5 + 10;
int n,a[N],nex[N];
std::map<int,bool>vis;
int gcd(int a,int b) {
return b == 0 ? a : gcd(b,a%b);
}
std::queue<pii>adjacent;//存储可以删除的歌曲序列
std::vector<int>ans;//存答案
int main() {
int T;scanf("%d",&T);
while(T--) {
scanf("%d",&n);
ans.clear();
vis.clear();
memset(nex,0,sizeof(nex));
for(int i = 1;i <= n;i ++) {
scanf("%d",&a[i]);
i == n ? nex[i] = 1 : nex[i] = i + 1;
}
// for(int i = 1;i <= n;i ++) cout << i << ' ' << nex[i] << '\n';
for(int i = 1;i <= n;i ++) {
if(gcd(a[i],a[nex[i]]) == 1) {
adjacent.push(MP(i,nex[i]));
}
}
while(!adjacent.empty()) {
pii p = adjacent.front();
adjacent.pop();
if(vis[p.first] || vis[p.second]) continue;
ans.pb(p.second);
nex[p.first] = nex[p.second];//注意链表的next指针维护操作
vis[p.second] = 1;
if(gcd(a[p.first],a[nex[p.second]]) == 1) {
adjacent.push(MP(p.first,nex[p.second]));
}
}
printf("%d",sz(ans));
for(int i = 0;i < sz(ans);i ++) printf(" %d",ans[i]);
puts("");
}
return 0;
}