C. Corners
题意:
题目给定一个n行m列且仅有1和0组成的矩阵,每次操作选择一个2*2的L型块,要求这个L块至少有1个1,然后将这个L块全部清0。求最多能操作多少次。
解题思路: 找规律和模拟。发现2*2正方形有4,3,2,1个1的个数时,可以进行相应的转换。
void solve() {
int n,m; cin>>n>>m;
rep(i,0,n-1) {
cin>>gt[i];
}
int sum = 0;
char ch;
rep(i,0,n-1) {
rep(j,0, m-1) {
pt[i][j] = (gt[i][j]=='1' ? 1: 0);
sum += pt[i][j];
}
}
int mi = 0x3f3f3f3f;
rep(i,0, n-2) {
rep(j,0, m-2) {
int s= 0;
s = ( pt[i][j] + pt[i][j+1] + pt[i+1][j] + pt[i+1][j+1]);
mi = min(s, mi);
}
}
int ans =0;
if(mi == 4) ans = sum - 2;
else if (mi == 3) ans = sum - 1;
else ans = sum;
cout<<ans<<endl;
}
E. Add Modulo 10
题意:
每个数组元素可以一直进行 ai + ai % 10。
问是否存在经过多次后,数组内元素值一样。
解题思路: 规律题。 首先可以想到mod10为0的元素不管怎么进行操作都是不变的,同时mod5可以经过一次操作,转换为0,进而与0一样。其他的都是可以转换为2,4,6,8,… 到最后以20为一个循环。数组mod10为0,5的转换为0后就停止,不能增加数字了,而其余的进行操作后,到2,4,6,8后表示后面都是一个20循环,可以到2,4,6,8停止,对其mod20。到最后,判断是否有不一样的数字。
void solve() {
int n; cin>>n;
vector<int> a(n);
for(int i = 0; i < n; ++i) {
cin>>a[i];
while(a[i]%10 != 2 && a[i]%10 != 0) {
a[i] += a[i] % 10;
}
if(a[i]%10 == 2) a[i] = a[i] % 20;
}
bool fg = 1;
rep(i,1,n-1) {
if(a[i] != a[i-1]) {
fg = 0; break;
}
}
if(fg) {
puts("Yes");
} else {
puts("No");
}
}
C. Mark and His Unfinished Essay
题意:
一个字符串 ,执行c个[l, r] 复制操作将其添加到末尾。q次询问,每次回答字符串该位置的字符ch
解题思路: 用pair或map将每一次复制append操作的前一个R的记录,并记录该次的复制开始l。查找用二分查找。
void solve() { // LL == long long
LL n, c,q,l,r; cin>>n>>c>>q;
string str; cin>>str;
map<LL,LL> mp; // map
LL ed = n; // 前一个的R,即前一个的字符串长度
while(c--) {
cin>>l>>r;
mp[ed + 1] = l; // 映射 这次复制的开始下标l
ed += r - l + 1; // +
}
while(q--) {
cin>>l;
/*
为什么二分,因为存在 [1, 50] 长度
进行两次操作 [51,67]--> 30 [68 70]--> 2 这个
*/
while(l > n) { // 得到大于查询l的第一个大于的地址并减到下一个地址
LL t = (--mp.upper_bound(l))->first;
LL dif = l - t; //
l = mp[t] + dif; // 得到下一个的L
}
cout<<str[l-1]<<endl;
}
}
总结
规律题没找找思路,以一个死思路一路走到黑了。下次一定要注意,一二十分钟没有ac就换思路。
对map<int,int>的 upper_bound(key) 有了更深的影响和学习。