A.2026(个人难度评价:洛谷红)
枚举模拟即可,如果数据范围较大可以使用数位dp
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define int long long
#define i128 __int128
#define pii pair<int,int>
#define tp tuple<int,int,int>
#define db double
const db INF=1e18;
const db pi=acos(-1);
const int mod=1e9+7;
const int inv2=500000004;
const db eps=1e-6;
const int inf=1e18;
const int N=1e6+10;
const int base=499;
int dcmp(double x){
if(fabs(x)<eps){
return 0;
}
return x<0?-1:1;
}
void debug(){
cout<<"Test:Wrong"<<'\n';
exit(0);
}
void solve(){
cout<<287926;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T=1;
//cin>>T;
while(T--)solve();
return 0;
}
B.不等式(个人难度评价:洛谷橙)
把能填的先填了,第一行后四个只能填2345或者1234,但是前者会使第4列有重复,所以第一***定为51234;
由此,(2,5)位置的数要大于4,所以只能填5,(3,5)不能填3,而第5列只剩下2,3可以填,所以(3,5)填2,(4,5)填3;
至此,(3,4)要满足大于2,而第三行3已经有有了,并且第4列4存在了,所以(3,4)只能填5;
(3,2)要满足大于(4,2),而第3行只剩1和4没被填,所以(3,2)只能填4,(3,3)填1;
(4,2)只剩2和5可以填,因为要满足小于4,所以(4,2)填2,(5,2)填5;
第5行只剩3和2没填,因为第3列已经填了2,所以只能(5,1)填2,(5,3)填3;
第3列还剩4和5没被填,但是第二行5被填了,所以(2,3)填4,(4,3)填5;
第二行还剩1和2没有填,因为第一列已经填过2了,所以(2,1)填1,(2,4)填2,
剩下两个空直接填入列没填过的数就完成了 答案:5123413425341524251325341
C.字典序(个人难度评价:洛谷橙)
cmp函数按照题意写出即可 时间复杂度:O(26nlog(n))
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
//#define int long long
#define i128 __int128
#define pii pair<int,int>
#define tp tuple<int,int,int>
#define db double
const db INF=1e18;
const db pi=acos(-1);
const int mod=1e9+7;
//const int inv2=500000004;
const db eps=1e-6;
//const int inf=1e18;
const int N=1e6+10;
const int base=499;
int dcmp(double x){
if(fabs(x)<eps){
return 0;
}
return x<0?-1:1;
}
void debug(){
cout<<"Test:Wrong"<<'\n';
exit(0);
}
struct node{
int cnt[26];
string s;
}a[N];
bool cmp(node n1,node n2){
for(int i=0;i<26;i++){
if(n1.cnt[i]!=n2.cnt[i]){
return n1.cnt[i]>n2.cnt[i];
}
}
return n1.s<n2.s;
}
void solve(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].s;
memset(a[i].cnt,0,sizeof(a[i].cnt));
for(auto c:a[i].s){
a[i].cnt[c-'a']++;
}
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++){
cout<<a[i].s<<" ";
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T=1;
//cin>>T;
while(T--)solve();
return 0;
}
D.括号序列(个人评价:洛谷橙)
用flag记录当前是否已经有'(',用t记录当前'('后的子串,直到遇到')'就计算子串并清空,每次遇到'('需要把子串清空 时间复杂度:O(n)
using namespace std;
#define ull unsigned long long
#define int long long
#define i128 __int128
#define pii pair<int,int>
#define tp tuple<int,int,int>
#define db double
const db INF=1e18;
const db pi=acos(-1);
const int mod=1e9+7;
const int inv2=500000004;
const db eps=1e-6;
const int inf=1e18;
const int N=1e6+10;
const int base=499;
int dcmp(double x){
if(fabs(x)<eps){
return 0;
}
return x<0?-1:1;
}
void debug(){
cout<<"Test:Wrong"<<'\n';
exit(0);
}
void solve(){
string s;
cin>>s;
string t="";
int flag=0;
int ans=0;
for(auto c:s){
if(c=='('){
flag=1;
t="";
}else if(c==')'&&flag){
int sum=0;
int now=0;
for(auto ch:t){
if(ch=='.'){
sum+=now;
now=0;
}else{
now=now*10+(ch-'0');
}
}
sum+=now;
ans=max(ans,sum);
t="";
flag=0;
}else if(flag){
t+=c;
}
}
cout<<ans;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T=1;
//cin>>T;
while(T--)solve();
return 0;
}
E.矩阵旋转(个人评价:洛谷黄)
发现d<=10,所以想到可以正难则反,倒着做时原来的顺时针旋转操作要改成逆时针,逆时针同理,计算出最终状态的(dx,dy)是由初始状态的那个坐标得到的 复杂度O(dq)
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define int long long
#define i128 __int128
#define pii pair<int,int>
#define tp tuple<int,int,int>
#define db double
const db INF=1e18;
const db pi=acos(-1);
const int mod=1e9+7;
const int inv2=500000004;
const db eps=1e-6;
const int inf=1e18;
const int N=1e6+10;
const int base=499;
int dcmp(double x){
if(fabs(x)<eps){
return 0;
}
return x<0?-1:1;
}
void debug(){
cout<<"Test:Wrong"<<'\n';
exit(0);
}
pii xuan(int xx1,int yy1,int xx2,int yy2,int op,int x,int y){
if(op==1){
return {xx1+yy2-y,yy1+x-xx1};
}else{
return {xx1+y-yy1,yy1+xx2-x};
}
}
struct node{
int op,x,y,len;
}qry[N];
void solve(){
int n;
cin>>n;
int q;
cin>>q;
for(int i=1;i<=q;i++){
int op,x,y,len;
cin>>op>>x>>y>>len;
qry[i]={op,x,y,len};
}
int d;
cin>>d;
for(int i=1;i<=d;i++){
int x,y;
cin>>x>>y;
for(int j=q;j>=1;j--){
auto[op,xx1,yy1,len]=qry[j];
int xx2=xx1+len-1;
int yy2=yy1+len-1;
if(x<xx1||x>xx2||y<yy1||y>yy2)continue;
auto f=xuan(xx1,yy1,xx2,yy2,op,x,y);
x=f.first;
y=f.second;
}
cout<<(x-1)*n+y<<'\n';
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T=1;
//cin>>T;
while(T--)solve();
return 0;
}
F.能量核心(个人评价:洛谷绿)
按位贪心,我们希望高位尽量存在于答案中.
所以对于每一位,若a[i]中当前位为1,我们尝试在b数组中加入当前位,对于b数组我们利用dp求出最大的能量区段数,使得每一个能量区段的当前异或值相等.
如果能量区段数>=m并且和m的奇偶性相同,那么合法,因为多出的偶数个能量区段的异或是零,把这偶数个能量区段并到一个能量区段就行了.
如果当前位合法,我们就得把b数组加入的当前位保留并更新ans,因为高位的优先级总是高于低位的,如果当前位不合法,我们就把当前位在b数组的操作撤销
时间复杂度O(30nlog(n))
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define int long long
#define i128 __int128
#define pii pair<int,int>
#define tp tuple<int,int,int>
#define db double
const db INF=1e18;
const db pi=acos(-1);
const int mod=1e9+7;
const int inv2=500000004;
const db eps=1e-6;
const int inf=1e18;
const int N=1e6+10;
const int base=499;
int dcmp(double x){
if(fabs(x)<eps){
return 0;
}
return x<0?-1:1;
}
void debug(){
cout<<"Test:Wrong"<<'\n';
exit(0);
}
int a[N];
int b[N];
int dp[N];
int pre[N];
void solve(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
int ans=0;
for(int i=30;i>=0;i--){
map<int,int>mp;
map<int,int>vis;
vis[0]=1;
mp[0]=0;
int tmp=ans+(1<<i);
for(int j=1;j<=n;j++){
if(a[j]>>i&1)b[j]^=(1<<i);
}
for(int j=1;j<=n;j++){
pre[j]=(pre[j-1]^b[j]);
if(vis[pre[j]^tmp]){
dp[j]=dp[mp[pre[j]^tmp]]+1;
if(dp[j]>dp[mp[pre[j]]]){
mp[pre[j]]=j;
vis[pre[j]]=1;
}
}else{
dp[j]=0;
}
}
// if(i==2){
// cout<<"test: "<<dp[n]<<'\n';
// }
if(dp[n]%2==m%2&&dp[n]>=m){
ans+=(1<<i);
}else{
for(int j=1;j<=n;j++){
if(b[j]>>i&1)b[j]-=(1<<i);
}
}
}
cout<<ans;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T=1;
//cin>>T;
while(T--)solve();
return 0;
}
G.字符串(个人评价:洛谷绿)
我们使用dp,dp[i]定义为以i为结尾的合法分割的最小分割次数.
我们发现合法的分割是存在范围的,若s[i,j]已经为合法子串(不是交替串并且长度<=k),那么s[i-1,j]在长度<=k的情况下必定是合法子串,因为他已经不可能是交替串了.
所以我们可以二分出对于结尾为j,最大的下标i,使得s[i,j]不是交替串,判断交替串可以使用奇数下标前缀和和偶数下标前缀和,当前的奇数下标的值之和为0且当前的偶数下标的值之和为偶数下标的数量,或者反之,都是交替串,再加上k的限制,我们找到了可以分割的范围[l,r].
利用单点修改,区间查询的线段树,我们可以得到当前合法分割的最小值 dp[j]=min(dp[l-1],....,dp[r-1])+1
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define int long long
#define i128 __int128
#define pii pair<int,int>
#define tp tuple<int,int,int>
#define db double
const db INF=1e18;
const db pi=acos(-1);
const int mod=1e9+7;
const int inv2=500000004;
const db eps=1e-6;
const int inf=1e18;
const int N=1e5+10;
const int base=499;
int dcmp(double x){
if(fabs(x)<eps){
return 0;
}
return x<0?-1:1;
}
void debug(){
cout<<"Test:Wrong"<<'\n';
exit(0);
}
int tr[N<<2];
int ls(int p){
return p*2;
}
int rs(int p){
return p*2+1;
}
void pushup(int p){
tr[p]=min(tr[ls(p)],tr[rs(p)]);
}
void build(int p,int s,int t){
if(s==t){
tr[p]=0;
return;
}
int mid=(s+t)>>1;
build(ls(p),s,mid);
build(rs(p),mid+1,t);
pushup(p);
}
void update(int p,int s,int t,int l,int r,int x){
if(l<=s&&t<=r){
tr[p]=x;
return;
}
int mid=(s+t)>>1;
if(l<=mid){
update(ls(p),s,mid,l,r,x);
}
if(mid+1<=r){
update(rs(p),mid+1,t,l,r,x);
}
pushup(p);
}
int query(int p,int s,int t,int l,int r){
if(l<=s&&t<=r){
return tr[p];
}
int mid=(s+t)>>1;
int ans=inf;
if(l<=mid){
ans=min(ans,query(ls(p),s,mid,l,r));
}
if(mid+1<=r){
ans=min(ans,query(rs(p),mid+1,t,l,r));
}
return ans;
}
int pre[N];
string s;
int check(int l,int r){
int len=r-l+1;
int lenji=len-len/2;
int lenou=len/2;
int sji=pre[r]-pre[r-(lenji-1)*2]+(s[r-(lenji-1)*2]-'0');
int sou=pre[r-1]-pre[r-1-(lenou-1)*2]+(s[r-1-(lenou-1)*2]-'0');
if(sji==lenji&&sou==0||sji==0&&sou==lenou)return 1;
else return 0;
}
void solve(){
int n,k;
cin>>n>>k;
cin>>s;
s='!'+s;
pre[1]=s[1]-'0';
for(int i=2;i<=n;i++){
pre[i]=pre[i-2]+(s[i]-'0');
}
build(1,1,n);
update(1,1,n,1,1,1);
for(int i=2;i<=n;i++){
int l=1,r=i-1,ans=-1;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid,i)){
r=mid-1;
}else{
ans=mid;
l=mid+1;
}
}
int dp=query(1,1,n,i-1,i-1)+1;
if(ans!=-1){
int l=max(1ll,i-k+1),r=ans;
if(l<=r){
if(l==1){
dp=1;
}else{
dp=min(dp,query(1,1,n,l-1,r-1)+1);
}
}
}
update(1,1,n,i,i,dp);
}
cout<<query(1,1,n,n,n)-1<<'\n';
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T=1;
cin>>T;
while(T--)solve();
return 0;
}
H.星海(个人评价:洛谷绿)
可以想到用最短路求解,瓶颈在于无法确定源点,所以我们使用次短路,因为对于一个计划星球来说到达它的最短路肯定是自己,所以次短路就是这个点到达别处星球的最小值(只要钦定一个点的次短路和最短路的出发点不同即可)
时间复杂度O(nlogn)
比较相似的一道题:2025浙江省赛F
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define int long long
#define i128 __int128
#define pii pair<int,int>
#define tp tuple<int,int,int>
#define db double
const db INF=1e18;
const db pi=acos(-1);
const int mod=1e9+7;
const int inv2=500000004;
const db eps=1e-6;
const int inf=1e18;
const int N=1e5+10;
const int base=499;
int dcmp(double x){
if(fabs(x)<eps){
return 0;
}
return x<0?-1:1;
}
void debug(){
cout<<"Test:Wrong"<<'\n';
exit(0);
}
int dis[N][2];
int st[N][2];
int vis[N][2];
int b[N];
vector<pii>g[N];
struct node{
int s,x,w,id;
bool operator<(node p)const{
return w>p.w;
}
};
void solve(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
g[i].clear();
dis[i][0]=inf;
dis[i][1]=inf;
st[i][0]=-1;
st[i][1]=-1;
vis[i][0]=0;
vis[i][1]=0;
}
for(int i=1;i<=m;i++){
int x,y,w;
cin>>x>>y>>w;
g[x].push_back({y,w});
g[y].push_back({x,w});
}
int k;
cin>>k;
priority_queue<node>q;
for(int i=1;i<=k;i++){
cin>>b[i];
q.push({b[i],b[i],0,0});
dis[b[i]][0]=0;
st[b[i]][0]=b[i];
}
while(q.size()){
auto[s,x,w,id]=q.top();
q.pop();
if(vis[x][id])continue;
vis[x][id]=1;
for(auto [y,d]:g[x]){
if(dis[y][0]>dis[x][id]+d){
dis[y][1]=dis[y][0];
dis[y][0]=dis[x][id]+d;
st[y][1]=st[y][0];
st[y][0]=s;
q.push({st[y][0],y,dis[y][0],0});
q.push({st[y][1],y,dis[y][1],1});
}else if(s!=st[y][0]&&dis[y][1]>dis[x][id]+d){
dis[y][1]=dis[x][id]+d;
q.push({st[y][1],y,dis[y][1],1});
}
}
}
int ans=inf;
for(int i=1;i<=k;i++){
ans=min(ans,dis[b[i]][1]);
}
cout<<ans<<'\n';
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T=1;
cin>>T;
while(T--)solve();
return 0;
}



京公网安备 11010502036488号