2021
砝码称重
砝码称重https://www.acwing.com/problem/content/3420
略有变形的01背包问题
先把所有砝码可能达到的最大总重sum计算出来,每次多讨论一个砝码时枚举1~sum之间的所有数,如果被标记过(表明之前已经得到过这个重量),我们可以在此数基础上加上当前砝码重量/减去当前砝码重量,并对得到的数值进行标记,并把当前讨论的砝码的单独的重量打上标记,这样一层一层推进。
#include<bits/stdc++.h>
using namespace std;
int n,a[110],ok[100010][110],sum;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];
}
ok[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=sum;j++)
{
if(ok[j][i-1])
{
ok[j+a[i]][i]=1;
ok[abs(j-a[i])][i]=1;
ok[j][i]=1;
}
}
ok[a[i]][i]=1;
}
int ans=0;
for(int i=1;i<=sum;i++)
if(ok[i][n]) ans++;
cout<<ans;
return 0;
}
异或数列
异或数列https://www.acwing.com/problem/content/3424/
博弈问题
先判断一下每组数内的所有数是否都出现两次(异或和为0),此时为平局情况。
若不为平局,则要比谁最后可以拿到二进制下最高位的有效的1。
于是先遍历所有数,按二进制数位统计每个数位上1的个数——
-
如果最高位的1有偶数个:无效,直接比较次最高位;
-
如果最高位的1有奇数个:
-
特判:如果最高位1只对应1个数,这个数一定会率先被拿走,所以是先手胜出;
-
若n的总数为奇数个,先手先拿最高位是1的数,若后手拿最高位是0的数,先手就拿最高位是0的数,若后手拿最高位是1的数,先手就拿最高位是1的数,最后是先手胜出;
-
若n的总数为偶数个,则含有奇数个最高位是0的数,后手有办法拿到最高位奇数个0和奇数个1,先手只能拿偶数个最高位1,后手胜出。
-
#include<bits/stdc++.h>
using namespace std;
int T;
int a[32];
int main()
{
cin>>T;
while(T--)
{
memset(a,0,sizeof(a));
int n;
cin>>n;
int ans=0;
for(int j=0;j<n;j++)
{
int x;
cin>>x;
ans^=x;
for(int i=1;i<=30&&x;i++)
{
if(x&1) a[i]++;
x>>=1;
}
}
if(!ans) cout<<0<<endl;
else
{
for(int i=30;i>0;i--)
{
if(a[i]==1)
{
cout<<1<<endl;
break;
}
else if(a[i]&1)
{
if(n&1) cout<<1<<endl;
else cout<<-1<<endl;
break;
}
}
}
}
return 0;
}
2020
七段码
并查集
//answer :80
#include<bits/stdc++.h>
using namespace std;
int mp[8][8],vis[8],fa[8],ans=0;
int find(int x)
{
if(fa[x]==x) return x;
else return fa[x]=find(fa[x]);
}
void dfs(int k)
{
if(k>7)
{
for(int i=1;i<=7;i++) fa[i]=i;
for(int i=1;i<=7;i++)
{
for(int j=1;j<=7;j++)
{
if(mp[i][j]&&vis[i]&&vis[j])
{
int x=find(i),y=find(j);
if(x!=y) fa[x]=y;
}
}
}
int cnt=0;
for(int i=1;i<=7;i++)
{
if(vis[i]&&fa[i]==i) cnt++;
}
if(cnt==1) ans++;
return;
}
vis[k]=1;
dfs(k+1);
vis[k]=0;
dfs(k+1);
}
int main()
{
mp[1][2]=mp[2][1]=1;
mp[1][6]=mp[6][1]=1;
mp[2][3]=mp[3][2]=1;
mp[2][7]=mp[7][2]=1;
mp[3][4]=mp[4][3]=1;
mp[3][7]=mp[7][3]=1;
mp[4][5]=mp[5][4]=1;
mp[5][6]=mp[6][5]=1;
mp[5][7]=mp[7][5]=1;
mp[6][7]=mp[7][6]=1;
dfs(1);
cout<<ans;
return 0;
}
子串分值
子串分值
https://www.acwing.com/problem/content/2868/
#include<std/c++.h>
using namespace std;
const int N=1e5+5;
int pre[N],next[N],a[27];
string s;
long long ans=0;
int main()
{
cin>>s;
int n=s.size();
s=' '+s;//让下标从1开始
for(int i=1;i<=n;i++)
{
pre[i]=a[s[i]-'a'];
a[s[i]-'a']=i;
}//滚动一轮,得到pre数组
for(int i=0;i<26;i++)
a[i]=n+1;//为了让next有初始的值(最后)
for(int i=n;i>0;i--)
{
next[i]=a[s[i]-'a'];
a[s[i]-'a']=i;
}//滚动一轮,得到next数组
for(int i=1;i<=n;i++)
ans+=(i-pre[i])*(next[i]-i)
//每个字符(设为ch)有一个贡献的区间 (上次出现ch的位置,下次出现ch的位置)
//从区间( pre[i],i)内任选一点, 从区间( next[i],i)内任选一点,s[i]在这样的两点构成的区间内只出现一次
//对于s[i],符合条件的区间有 (i-pre[i])*(next[i]-i)个
cout<<ans;
return 0;
}
2019
迷宫
answer:DDDDRRURRRRRRDRRRRDDDLDDRDDDDDDDDDDDDRDDRRRURRUURRDDDDRDRRRRRRDRRURRDDDRRRRUURUUUUUUULULLUUUURRRRUULLLUUUULLUUULUURRURRURURRRDDRRRRRDDRRDDLLLDDRRDDRDDLDDDLLDDLLLDLDDDLDDRRRRRRRRRDDDDDDRR
典型的·BFS,值得关注的就是这种记录路径的办法。
#include<bits/stdc++.h>
using namespace std;
struct position
{
int x,y;
string path;
};
int maze[55][55];
int vis[55][55];
int dx[4]={1,0,0,-1};
int dy[4]={0,-1,1,0};
char direction[4]={'D','L','R','U'};
vector<char>vec;
queue<position>q;
bool judge(position next)
{
if(!maze[next.x][next.y]&&next.x>=1&&next.x<=30&&next.y>=1&&next.y<=50&&!vis[next.x][next.y])
return true;
return false;
}
void bfs()
{
position start;
start.x=1,start.y=1;
q.push(start);
while(q.size())
{
position now=q.front();
q.pop();
if(now.x==30&&now.y==50)
{
cout<<now.path;
return;
}
vis[now.x][now.y]=1;
for(int i=0;i<4;i++)
{
position next;
next.x=now.x+dx[i];
next.y=now.y+dy[i];
next.path=now.path+direction[i];
if(judge(next)) q.push(next);
}
}
}
int main()
{
for(int i=1;i<=30;i++)
for(int j=1;j<=50;j++)
scanf("%1d",&maze[i][j]);
bfs();
return 0;
}
外卖店优先级
外卖店优先级https://www.acwing.com/problem/content/1243/
直接暴力肯定超时,我想着写O(m)的做法,结果错了六发。。。(腹诽:还不如暴力骗80分)要注意的小细节非常多。
大体的思路就是先把题给的数据存到对应编号的vec里,然后遍历这n家外卖店的vec,对于每家店的vec:
1.先把所有数据排序!(题目给的订单不是按照时间顺序排列的)
sort(vec[i].begin(),vec[i].end());
2.第一个数据:除了加2个优先级之外啥也不干(在第一个订单出现之前优先级一直都是0)
3.从第二个数据(如果存在的话)一直到最后一个数据:每次先处理空档造成的优先级下降(从vec[i][j]到vec[i][j-1]有(vec[i][j]-vec[i][j-1]-1)个时间段),如果优先级下降到小于等于3,标记被清出优先缓存,又由于当前订单会使得优先级加2,如果优先级大于5了,标记进入优先缓存。
if(vec[i][j]-vec[i][j-1]-1>0) priority=max(0,priority-(vec[i][j]-vec[i][j-1]-1)); if(priority<=3) flag=0; priority+=2; if(priority>5) flag=1;
3.从最后一个数据到T个时刻过去:从最后一个数据到T之间还有(T-vec[i][vec[i].size()-1])个时间段,会使优先级下降,最后判断一下是否会下降到小于等于3即可
priority=max(0,priority-(T-vec[i][vec[i].size()-1])); if(priority>3&&flag) cnt++;
全部代码:
#include<bits/stdc++.h>
using namespace std;
vector<int>vec[100001];
int N,M,T,cnt;
int main()
{
cin>>N>>M>>T;
while(M--)
{
int t,num;
scanf("%d%d",&t,&num);
vec[num].push_back(t);
}
for(int i=1;i<=N;i++)
{
if(vec[i].empty()) continue;
sort(vec[i].begin(),vec[i].end());
int priority=0,flag=0;
for(int j=0;j<vec[i].size();j++)
{
//cout<<vec[i][j]<<' ';
if(j==0)
{
priority+=2;
continue;
}
if(vec[i][j]-vec[i][j-1]-1>0)
priority=max(0,priority-(vec[i][j]-vec[i][j-1]-1));
if(priority<=3) flag=0;
priority+=2;
//cout<<" priority:"<<priority<<' ';
if(priority>5) flag=1;
}
priority=max(0,priority-(T-vec[i][vec[i].size()-1]));
//cout<<"last:"<<priority<<endl;
if(priority>3&&flag) cnt++;
}
cout<<cnt;
return 0;
}
修改数组
修改数组https://www.acwing.com/problem/content/1244/
#include<bits/stdc++.h>
using namespace std;
int N;
int a[100001],fa[2000000];
int find(int x)
{
if(fa[x]==x) return x;
else return fa[x]=find(fa[x]);
}
int main()
{
cin>>N;
for(int i=1;i<=2000000;i++) fa[i]=i;
for(int i=1;i<=N;i++)
{
scanf("%d",&a[i]);
if(find(a[i])==a[i])
fa[a[i]]++;
else
{
a[i]=find(a[i]);
fa[a[i]]++;
}
cout<<a[i]<<' ';
}
return 0;
}