1.Codeforces Round #590 (Div. 3) C
题意:两行管道,有六种管道,每个管道都可以旋转,问能不能通到右下角。
从左往右通就好了,从纵向看来,每步(每两个管道)只要如果连通上一步的终点的是一个直管道或者这两个都是弯管道就可以通到下一步。直管道下一步位置不变,两个弯管道位置变化,出现其它情况都会终止通道。所以只需要记录当前管道连通位置,并判断下一位置的管道即可。当然,最后还要看下是不是连通的右下角。
#include<iostream>
#include<iomanip>
#include<fstream>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<cstdio>
#include<map>
#include<queue>
#include<vector>
#include<utility>
#include<ostream>
#include<istream>
typedef long long ll;
using namespace std;
#define mod 1e9+7
#define PI acos(-1.0)
const ll maxn=2*1e5;
const int mx=(1<<20)+99;
ll n,m,x,ans,aans,pos,a[maxn+10],b[maxn+10];
char c;
int main()
{
cin.tie(0);
ios::sync_with_stdio(0);
int t;
cin>>t;
for(int o=1;o<=t;o++)
{
cin>>n;
for(int i=1;i<=2*n;i++)
{
cin>>c;
if(i>n)
b[i-n]=int(c-'0');
else
a[i]=int(c-'0');
}
pos=1; ans=1;
for(int i=1;i<=n;i++)
{
//cout<<"pos: "<<pos<<" "<<endl;
if(pos==1)
{
if(a[i]<=2) continue;
else if(a[i]>=3&&b[i]>=3)
{ pos=2; continue; }
else { ans=0; break; }
}
else
{
if(b[i]<=2) continue;
else if(a[i]>=3&&b[i]>=3)
{ pos=1; continue; }
else { ans=0; break; }
}
}
if(pos==1) ans=0;
if(ans) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
2.Codeforces Round #590 (Div. 3) E
今晚还要打场div.2比赛,所以先水上官方代码吧,明天上午再看下。
#include <bits/stdc++.h>
using namespace std;
int main() {
#ifdef _DEBUG
freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif
int n, m;
cin >> n >> m;
vector<int> a(m);
for (int i = 0; i < m; ++i) {
cin >> a[i];
--a[i];
}
vector<long long> res(n);
for (int j = 0; j < m - 1; ++j) {
res[0] += abs(a[j] - a[j + 1]);
}
vector<int> cnt(n);
vector<vector<int>> adj(n);
for (int i = 0; i < m - 1; ++i) {
int l = a[i], r = a[i + 1];
if (l != r) {
adj[l].push_back(r);
adj[r].push_back(l);
}
if (l > r) swap(l, r);
if (r - l < 2) continue;
++cnt[l + 1];
--cnt[r];
}
for (int i = 0; i < n - 1; ++i) {
cnt[i + 1] += cnt[i];
}
for (int i = 1; i < n; ++i) {
res[i] = res[0] - cnt[i];
for (auto j : adj[i]) {
res[i] -= abs(i - j);
res[i] += j + (j < i);
}
}
for (int i = 0; i < n; ++i) {
cout << res[i] << " ";
}
cout << endl;
return 0;
}
3.Codeforces Round #590 (Div. 3) B1
看第六题。
4.Codeforces Round #590 (Div. 3) A
题意:给定n个数,使这n个数相等,且和不小于原数组总和的情况下尽可能小,求单个数的最小值。
#include<iostream>
#include<iomanip>
#include<fstream>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<cstdio>
#include<map>
#include<queue>
#include<vector>
#include<utility>
#include<ostream>
#include<istream>
typedef long long ll;
using namespace std;
#define mod 1e9+7
#define PI acos(-1.0)
const ll maxn=1e5;
const int mx=(1<<20)+99;
ll n,m,ans,aans,a[200];
int main()
{
cin.tie(0);
ios::sync_with_stdio(0);
int t;
cin>>t;
for(int o=1;o<=t;o++)
{
cin>>n;
aans=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
aans+=a[i];
}
if(aans%n) cout<<aans/n+1<<endl;
else cout<<aans/n<<endl;
}
return 0;
}
5.Codeforces Round #590 (Div. 3) D
题意:给定一个字符串,求给定下标当前字符种类。期间会有修改操作,将字符串种任意位置改为任意字母。
第一次直接数,毫无疑问超时。第二次用前缀和计算试试,还是超时。所以说应该用树状数组或者线段树解决,回顾了一下这两个工具的用法后明白应该用线段树解决。不过,我还是看到有人用树状数组做的,看起来还比线段树简单。
树状数组:
#include <iostream>
#include <stdio.h>
#include <map>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
int n ;
struct tree{
int a[N];
int lowbit(int x){
return x&(-x);
}
void update(int p,int x){
for(int i=p;i<=n;i+=lowbit(i))
a[i] += x;
}
int sum(int p){
int res = 0;
for(int i=p;i>0;i-=lowbit(i))
res += a[i];
return res;
}
int query(int l,int r){
return sum(r) - sum(l-1);
}
}ch[30];
string s;
int main(){
cin >> s;
n = s.length();
int m,op,l,r;
char cha;
for(int i=0;i<n;++i){
ch[s[i]-'a'].update(i+1,1);
}
cin >> m;
while(m--){
cin >> op;
if(op == 1){
cin >> l >> cha;
ch[s[l-1]-'a'].update(l,-1);
s[l-1] = cha;
ch[s[l-1]-'a'].update(l,1);
}else{
cin >> l >> r;
int ans = 0;
for(int i=0;i<26;++i){
if(ch[i].query(l,r)>0) ans++;
}
cout<<ans<<endl;
}
}
return 0;
}
-
线段树:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1e5 + 5;
char str[maxn], op[3];
int n, l, r, x, fi[30], permt[30], tmp_permt[30];
struct SegmentTree {int l, r, a[30]; }t[maxn * 4];
inline void build(int s, int l, int r) {
t[s].l = l, t[s].r = r;
for(int i = 0; i <= 26; i ++)
t[s].a[i] = 0;
if(l == r) return;
int mid = (l + r) / 2;
build(s * 2, l, mid);
build(s * 2 + 1, mid + 1, r);
}
inline void insert(int s, int l, int r, int x) {
if(l <= t[s].l && r >= t[s].r) {
t[s].a[x] ++;
return;
}
int mid = t[s].l + t[s].r >> 1;
if(l <= mid) insert(s * 2, l, r, x);
else insert(s * 2 + 1, l, r, x);
t[s].a[x] = t[s * 2].a[x] + t[s * 2 + 1].a[x];
}
inline void change(int s, int l, int r, int y, int x) {
if(l <= t[s].l && r >= t[s].r) {
t[s].a[x] ++;
t[s].a[y] --;
return;
}
int mid = (t[s].l + t[s].r) >> 1;
if(l <= mid) {
change(s * 2, l, r, y, x);
t[s].a[x] = t[s * 2].a[x] + t[s * 2 + 1].a[x];
t[s].a[y] = t[s * 2].a[y] + t[s * 2 + 1].a[y];
} else {
change(s * 2 + 1, l, r, y, x);
t[s].a[x] = t[s * 2].a[x] + t[s * 2 + 1].a[x];
t[s].a[y] = t[s * 2].a[y] + t[s * 2 + 1].a[y];
}
}
inline void query(int s, int l, int r) {
if(l <= t[s].l && r >= t[s].r) {
for(int i = 0; i <= 26; i ++)
permt[i] += t[s].a[i];
return;
}
int mid = (t[s].l + t[s].r) / 2;
if(l <= mid) query(s * 2, l, r);
if(mid< r) query(s * 2 + 1, l, r);
}
inline void out(void)
{
for(int i=0;i<=26;i++)
permt[i]=0;
query(1,1,15);
for(int i=0;i<=26;i++)
printf("%d%c ",permt[i],i+'a');
puts("");
for(int i=0;i<=26;i++)
permt[i]=0;
}
int main()
{
cin>>str+1;
cin>>n;
build(1,1,strlen(str+1));
for(int i=1;i<=strlen(str+1);i++)
insert(1,i,i,str[i]-'a');
for(int i=1;i<=n;i++)
{
cin>>op;
if(op[0]=='1')
{
cin>>x>>op;
change(1,x,x,str[x]-'a',op[0]-'a');
str[x]=op[0];
}
else
{
memset(permt,0,sizeof(permt));
cin>>l>>r;
int sum=0;
query(1,1,r);
memcpy(tmp_permt,permt,sizeof(permt));
memset(permt,0,sizeof(permt));
query(1,1,l-1);
for(int i = 0;i<=26;i++)
{
tmp_permt[i]-=permt[i];
if(tmp_permt[i]>0) sum++;
}
cout<<sum<<endl;
}
}
return 0;
}
6.Codeforces Round #590 (Div. 3) B2
题意:将会有n条信息发过来,屏幕上同时最多存在m个人的信息。当屏幕人数满了,如果下一条信息是屏幕上的某个人发的,那么将会直接显示在屏幕上,否则将屏幕最下方的人删除后将此条信息放到屏幕顶部。求最终留在屏幕上的人及其顺序。
当时一看就感觉应该用队列,之后看n,m范围很大觉得应该用map。再快写完后发现顺序不对但队列只能弹出队首元素,算了一下如果再用一个数组存储元素后再倒过来输出应该不超时,于是索性就这么做了。当然用双向队列可以省掉这一步。
#include<iostream>
#include<iomanip>
#include<fstream>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<cstdio>
#include<map>
#include<queue>
#include<vector>
#include<utility>
#include<ostream>
#include<istream>
typedef long long ll;
using namespace std;
#define mod 1e9+7
#define PI acos(-1.0)
const ll maxn=1e5;
const int mx=(1<<20)+99;
ll n,m,x,ans,aans,a[2*maxn+10];
map<ll,ll>mp;
int main()
{
cin.tie(0);
ios::sync_with_stdio(0);
//int t;
//cin>>t;
//for(int o=1;o<=t;o++)
//{
cin>>n>>m;
queue<ll>q;
mp.clear();
for(int i=1;i<=n;i++)
{
cin>>x;
if(mp.count(x)) continue;
else
{
//cout<<x<<" "<<mp[x]<<endl;
if(q.size()<m)
{
q.push(x);
}
else
{ mp.erase(q.front()); q.pop(); q.push(x); }
mp[x]=1;
}
}
cout<<q.size()<<endl;
aans=q.size();
for(int i=1;i<=aans;i++)
{
a[i]=q.front();
q.pop();
}
for(int i=aans;i>0;i--)
cout<<a[i]<<" ";
cout<<endl;
//}
return 0;
}
-
总结:这次的题目偏简单,感觉重点考察的是一些工具的用法。不过这样正好,就看代码写的顺不顺了。前面还好,队列的一些函数我不太确定还是查了查(比如队列没有clear函数),而要用到线段树时就得大搜一番了。所以,这些工具类的东西还是很有用的,做题时尽量练习使用,以熟练掌握。