周总结(还需要再认真看学习比如Strange Balls,预处理)
我按照时间从近到远的顺序写的
1.友谊赛(2/9)
打的一坨,感觉最近状态不是很好,需要调整一下把心态正回来,要更加专注才行。
注意读题,不是替换区间的字符串,而是替换字符,并且题目的要求是替换的区间是越来越小的
,意思就是替换的字符区间会缩小。我的写法是用mutilset从小到大记录,然后用头去比较,
如果头不是最小就跟他换,set里面的最小是rfind()去找的,然后为了让区间变小,我把大于前面
出现过的区间最小的全部丢掉。但是这样操作是有问题的。正确做法应该是让区间不断减小,如果左边大于右边
就让右边大于左边的字符在set里面删除,直到小于为止,然后替换,替换之后,这两个数也不能用在set中erase,l++,r--,
直到l>=r就break;
#include <bits/stdc++.h>
using namespace std;
multiset<char>st;
int main(){
int n;
cin>>n;
string s;
cin>>s;
for(int i=0;i<n;i++){
st.insert(s[i]);
}
int l=0,r=n-1;
while(l<r){
if(s[l]!=*st.begin()){
while(s[r]!=*st.begin()){
st.erase(st.find(s[r]));
r--;
}
swap(s[l],s[r]);
st.erase(st.find(s[l]));
l++;
st.erase(st.find(s[r]));
r--;
}else{
st.erase(st.find(s[l]));
l++;
}
}
cout<<s;
}
A.Tiling Challenge
牛魔题,搞我心态,题读错了,我读成有无十字的.以及有十字的点的话他们有没有重复出现的点。
题目的意思是:能不能把所有的.换成#。。。服了
最近在练dfs,就直接dfs扫了一遍wa8了,后面用两重for就过了。
#include <bits/stdc++.h>
using namespace std;
int n;
char v[51][51];
int vis[51][51];
bool judge(int x, int y) {
if (x <= 1 || x >= n || y <= 1 || y >= n) return false;
if (v[x][y] == '.' && v[x - 1][y] == '.' && v[x + 1][y] == '.' && v[x][y - 1] == '.' && v[x][y + 1] == '.') return true;
return false;
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> v[i][j];
}
}
int ans=0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (judge(i, j)) {
ans++;
v[i][j]='#';
v[i - 1][j]='#';
v[i + 1][j] ='#';
v[i][j - 1] ='#';
v[i][j + 1] ='#';
}
}
}
if(ans!=0){
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (v[i][j] == '.') {
cout << "NO";
return 0;
}
}
}
cout << "YES";
}else
cout<<"NO";
return 0;
}
D - All Assign Point Add
这道题就是考怎么去思考快速给数组全部赋值,我一开始打算用fill和vector直接赋值,全部超时了。
后面是这样去思考的,每一次全部赋值,如果这个值后面没有修改过,就一直是被赋值的数,修改了,还需要判断有没有被赋值过,如果没有
被赋值过,需要先赋值再加,如果已经赋值了,那就直接加上新的值,输出的值也要判断一下,赋值刷新了并且修改的,赋值没有修改的,没有赋值的
三类讨论一下就行。
#include <bits/stdc++.h>
using namespace std;
long long n;
vector<long long> v;
set<long long>st;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
v.resize(n + 1);
for (int i = 1; i <= n; i++) {
cin >> v[i];
}
long long q;
int pd=0;
long long w=0;
cin >> q;
while (q--) {
long long x, y, z;
cin >> x;
if (x == 1) {
cin >> y;
pd=1;
w=y;
st.clear();
} else if (x == 2) {
cin >> y >> z;
if(pd==1&&st.find(y)==st.end()){
v[y]=w;
st.insert(y);
}
v[y] += z;
} else {
cin >> y;
if(pd==1&&st.find(y)==st.end())
cout << w << '\n';
else if(pd==1&&st.find(y)!=st.end()){
cout<<v[y]<<'\n';
}else
cout<<v[y]<<'\n';
}
}
}
D. Walk on Matrix
构造题,我的噩梦
首先我们可以想怎么去构造一个满足条件的通解。
注意构造题,我们尽量去找通解。
如果是2x3的矩阵,
我们找一个2的几次方大于3*10的5次方的数
再找一个小于它的数
排列起来是
2 1 0
n 2 n
只有三条路
1 & N = 0
2 & N = N
走2那条路
#include<bits/stdc++.h>
using namespace std;
#define int long long
/*
https://codeforces.com/problemset/problem/1503/B
*/
#define endl '\n'
typedef pair<int,int> pii;
typedef unsigned long long ull;
typedef long long ll;
const int N = 2e5+5,M=20,mod=998244353,P=131,INF=2e9;
int ans[3][2];
void solve(){
int k;
cin>>k;
int s=0,p=k;
while(p){
s++;
p>>=1;
}
cout<<3<<" "<<2<<endl;
ans[0][0]=(1<<s+1)-1;
ans[0][1]=k;
ans[1][0]=1<<s;
ans[1][1]=(1<<s+1)-1;
ans[2][1]=(1<<s)-1;
for(int i=0;i<3;i++){
for(int j=0;j<2;j++){
cout<<ans[i][j]<<" ";
}
cout<<endl;
}
}
void fast(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
}
signed main(){
fast();
int t=1;
// cin>>t;
while(t--)solve();
return 0;
}
- SMU Summer 2024 Contest Round 5(3/7)
Robot Takahashi
按照 Wi排个序,算一下前缀后缀 1 和 0 的个数就行了。答案大概是一个 max(pi+si+1)的形式。
有一个小细节:排序之后 Wi=Wi+1时无法在 i,i+1之间断开,要特判。我因为这个 WA 了一发。
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
for(;(c<'0'||c>'9');c=getchar()){if(c=='-')f=-1;}
for(;(c>='0'&&c<='9');c=getchar())x=x*10+(c&15);
return x*f;
}
const int MN=2e5+5;
int n,ans;
string s;
struct Node{int v,p;}a[MN];
int pre[MN],suf[MN];
signed main(void){
cin>>n>>s;
for(int i=1;i<=n;i++)cin>>a[i].v,a[i].p=(s[i-1]=='1');
sort(a+1,a+n+1,[](const Node &x,const Node &y){
return x.v<y.v;
});
for(int i=1;i<=n;i++)pre[i]=pre[i-1]+(a[i].p==0);
for(int i=n;i>=1;i--)suf[i]=suf[i+1]+(a[i].p==1);
for(int i=0;i<=n;i++){
if(a[i].v!=a[i+1].v){
ans=max(ans,pre[i]+suf[i+1]);
}
}
cout<<ans<<endl;
return 0;
}
Connect 6
暴力题。。。
#include <bits/stdc++.h>
using namespace std;
using ll =long long;
ll n,m,t;
vector<string>v(100010);
ll a[1000010];
void solve(){
cin>>n;
for(int i=0;i<n;i++){
cin>>v[i];
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
int pd=0;
for(int k=j;k<=j+5;k++){
if(k<n){
if(v[i][k]=='#')pd++;
if(pd>=4){
cout<<"Yes";
return;
}
}
}
pd=0;
for(int k=i;k<=i+5;k++){
if(k<n){
if(v[k][j]=='#')pd++;
if(pd>=4){
cout<<"Yes";
return;
}
}
}
pd=0;
for(int k=0;k<=5;k++){
if(i+5<n&&j+5<n){
if(v[i+k][j+k]=='#')pd++;
if(pd>=4){
cout<<"Yes";
return;
}
}
}
pd=0;
for(int k=0;k<=5;k++){
if(i-5>=0&&j+5<n){
if(v[i-k][j+k]=='#')pd++;
if(pd>=4){
cout<<"Yes";
return;
}
}
}
}
}
cout<<"No";
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}
赛时看不懂题目,赛后也想了很久才明白,有点像栈,它的意思是存数像栈一样,当n个数上的n个球时,
就会删除,然后问你每次添加球后的状态——个数,我们每次存进去个数,相同加加,不相同就push下一个,如果当前
个数达到n个,就把stack最顶上的pop掉,以此类推。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mxn=1e6+10;
const int mxe=1e6+10;
const int Inf=1e18;
stack<pair<int,int> > S;
int n;
int a[mxn];
void solve(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
int cnt=0;
for(int i=1;i<=n;i++){
if(S.empty()){
S.push({a[i],1});
cnt++;
}else if(S.top().first==a[i]){
S.top().second++;
cnt++;
if(S.top().second==a[i]){
cnt-=a[i];
S.pop();
}
}else{
S.push({a[i],1});
cnt++;
}
cout<<cnt<<'\n';
}
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;//cin>>__;
while(t--)solve();return 0;
}
思路:为了快速获得x位置之后第一个为-1的数,考虑使用并查集,连通当前点和下一个点的最前面点。
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define endl "\n"
#define LL long long
using namespace std;
const int N = 2e6 + 10, MOD = 1048576;
int Q;
LL p[N], v[N];
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main() {
IOS;
for (int i = 0; i < 1048576; i ++ ) p[i] = i, v[i] = -1;
cin >> Q;
while (Q -- ) {
int t;
LL x;
cin >> t >> x;
if (t == 1) {
LL k = find(x % MOD);
v[k] = x;
p[k] = (k + 1) % MOD;
}
else cout << v[x % MOD] << endl;
}
return 0;
}
- SMU Summer 2024 Contest Round 4
问你Bci=Ai,就是有多少个c下标的b数组里面多少个和a相等。用一个map存数量就行。
#include <bits/stdc++.h>
using namespace std;
using ll =long long;
ll n;
ll a[100010];
ll b[100010];
ll c[100010];
map<ll,ll>mp;
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>b[i];
for(int i=1;i<=n;i++)cin>>c[i];
for(int i=1;i<=n;i++){
mp[b[c[i]]]++;
}
ll ans=0;
for(int i=1;i<=n;i++){
if(mp[a[i]]!=0)ans+=mp[a[i]];
}
cout<<ans;
}
H and V
问你选择任意个数行任意个数列,使得剩下的#为k个。
我们可以使用二进制枚举每种情况就可以算出来。
#include <bits/stdc++.h>
int n,m,k;
char a[10][10];
int main() {
ios::sync_with_stdio(false);cin.tie(0);
cin>>n>>m>>k;
int sum=0;
for(int i=0;i<n;++i){
for(int j=0;j<m;++j){
cin>>a[i][j];
if(a[i][j]=='#') sum++;
}
}
int cnt=0;
int ans=0;
for(int i=0;i<(1<<n);++i){
for(int j=0;j<(1<<m);++j){
cnt=0;
for(int r=0;r<n;++r){
for(int c=0;c<m;++c){
if( ((i&(1<<r)) || (j&(1<<c)))&& a[r][c]=='#') cnt++;
}
}
if(cnt==sum-k) ans++;
}
}
cout<<ans<<endl;
return 0;
}
Sum of Divisors
思路:预处理,预处理每个数,它的倍数约它是正约数,预处理每个数的正约数的数量。然后加就行
#include <bits/stdc++.h>
using namespace std;
const long long MAXN = 10000001;
long long divisors[MAXN + 1];
void sieve() {
for (long long i = 1; i <= MAXN; i++) {
for (long long j = i; j <= MAXN; j += i) {
divisors[j]++;
}
}
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
long long n;
cin >> n;
sieve(); // 预处理每个数的因数个数
long long sum = 0;
for (long long i = 1; i <= n; i++) {
sum += divisors[i] * i;
}
cout << sum;
return 0;
}
Red and Green Apples
思路:思维题,我一开始单独处理红苹果,绿苹果,无色苹果分别对这两个处理。导致一直有点过不了。
我们应该把前x大的红苹果和前y大的绿苹果拿出来放一起成新的苹果,然后拿无色苹果和x+y里面比较,替换就行。
代码
#include <bits/stdc++.h>
using namespace std;
using ll =long long;
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
ll x,y,a,b,c;
cin>>x>>y>>a>>b>>c;
vector<ll>A(a+1);
vector<ll>B(b+1);
vector<ll>C(c+1);
for(int i=1;i<=a;i++)cin>>A[i];
for(int i=1;i<=b;i++)cin>>B[i];
for(int i=1;i<=c;i++)cin>>C[i];
sort(A.rbegin(),A.rend());
sort(B.rbegin(),B.rend());
sort(C.rbegin(),C.rend());
vector<ll>res(a+b);
res.resize(x + y);
merge(A.begin(),A.begin()+x,B.begin(),B.begin()+y,res.begin());
A.assign(res.begin(),res.end());
sort(A.begin(),A.end());
int i = 0, j = 0;
while (i < c && j < x+y ){
if (C[i] > A[j]) {
A[j] = C[i];
++i;
}
++j;
}
ll sum=0;
for(int i=0;i<x+y;i++)sum+=A[i];
cout<<sum;
}
Rem of Sum is Num
思路:前缀和取余,记录个数
#include <bits/stdc++.h>
using namespace std;
using ll =long long;
const ll N =10000010;
ll prefix[N];
ll v[N];
map<int,int> mp;
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
ll n,k;
cin>>n>>k;
ll ans=0;
for(int i=1;i<=n;i++)cin>>v[i];
for(int i=1;i<=n;i++)prefix[i]+=prefix[i-1]+v[i];
for(int i=1;i<=n;i++)prefix[i] = (prefix[i] - i)%k;
int pos = min(n,k-1);
ll sum = 0;
for(int i= 0 ;i<=pos;i++)
{
sum+=mp[prefix[i]];
mp[prefix[i]] ++;
}
for(int i=pos+1;i<=n;i++)
{
mp[prefix[i-k]] --;
sum+=mp[prefix[i]];
mp[prefix[i]]++;
}
cout<<sum<<endl;
}
本周总结:
最近状态下滑,在复习学习dfs和bfs的问题,同时回顾了上个星期学的二分等,有了一些收获,但是感觉对一些问题比如二分图,
dp的学习还很浅,需要这个假期认认真真去学。。。加油吧,下个星期把状态找回来,坚持,并且学习新的东西,在学校要有收获。。