week2
蓝桥杯模拟赛 2
思路:当下几个字符组成数字n,输出n个当前字符,否则直接输出
string a,ans; cin>>a; for(int i=0;i<a.size();++i){ if(i<a.size()-1&&a[i]>=65&&a[i+1]<65){ int k=i+2; ll t=a[i+1]-'0'; while(a[k]<65&&k<a.size()){ t=t*10+(a[k]-'0'); k++; } for(ll j=0;j<t;++j)ans+=a[i]; i=k-1; } else{ ans+=a[i]; } } cout<<ans;
思路:输入时判断最大最小和统计总分
int n,a[N],ma=-1,mi=101; ll s=0; cin>>n; for(int i=0;i<n;++i){ cin>>a[i]; if(a[i]>ma)ma=a[i]; if(a[i]<mi)mi=a[i]; s+=a[i]; } cout<<ma<<'\n'<<mi<<'\n'; cout<<fixed<<setprecision(2)<<double(s)/double(n);
思路:除到小于0就停止
ll n; cin>>n; cout<<n<<' '; for(ll i=n;i>0;){ i>>=1; if(i>0)cout<<i<<' '; }
思路:注意前导0和后缀0
string a[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; string b,x,y; cin>>b; x=b.substr(0,3); y=b.substr(3,2); for(int i=0;i<12;++i) if(x==a[i]){ cout<<i+1<<' ';break; } if(y[0]!='0')cout<<y[0]; cout<<y[1];
思路:判断年的反转是否为合法的月日,是否满足ababbaba
bool check_vaild(int n) { int year = n / 10000 , month = n % 10000 / 100 , day = n % 100; if(month < 0 || month > 12) return false; if(day < 0 || (day > days[month] && month != 2)) return false; int x = 0; if(month == 2) x = year % 4 == 0 && year % 100 || year % 400 == 0; if(day > days[month] + x) return false; return true; } bool check_ABAB(int n) { int a = n / 10000000 , b = n / 1000000 % 10 , c = n /100000 % 10 , d = n / 10000 % 10; if(a == c && b == d && a != b) return true; return false; } int main() { int n; cin>>n; int falg = 1; for(int i = n / 10000;i < 10000;i ++) { int x = i , t = i; for(int j = 0;j < 4;j ++) x = x*10 + t%10 , t /= 10; if(check_vaild(x) && x > n && falg) { printf("%d\n",x); falg = 0; } if(check_vaild(x) && check_ABAB(x) && x > n) { cout<<x; break; } } return 0; }
思路:每加一条不重合直线,s都会加一,若该线与已存的直线有一个交点则s++,且每个交点需不同,用set存即可
int main(){ cin.tie(0),cout.tie(0); int n,s=1; double a,b; set<pair<double,double>>l; cin>>n; for(int i=0;i<n;++i){ cin>>a>>b; if(l.count({a,b})==1)continue; if(l.size()>0) { set<pair<double,double> >p; pair<double,double> pp; for (auto t: l) { int c = t.first, d = t.second; if (a == c)continue; pp.first = (b - d) / (c - a), pp.second = a * pp.first + b; p.insert(pp); } s+=p.size(); } l.insert({a,b}); s++; } cout<<s; return 0; }
思路:只能从格子的左和上走到该格,且边界都只有一条路,更新到每个格子的方案数
int main(){ cin.tie(0),cout.tie(0); cin>>n>>m; for(int i=1;i<=n;++i)a[i][1]=1; for(int i=1;i<=m;++i)a[1][i]=1; for(int i=2;i<=n;++i) for(int j=2;j<=m;++j) if(i%2!=0||j%2!=0)a[i][j]=a[i-1][j]+a[i][j-1]; cout<<a[n][m]; return 0; }
思路:将每个结果转化成p进制数,乘数大于等于10也需转化
int main(){ cin.tie(0),cout.tie(0); int p; vector<int>a; cin>>p; for(int i=1;i<p;++i){ for(int j=1;j<=i;++j){ if(i>=10){ cout<<char('A'+i-10)<<'*'; } else cout<<i<<'*'; if(j>=10)cout<<char('A'+j-10)<<'='; else cout<<j<<'='; a.clear(); int t=i*j; while(t){ a.push_back(t%p); t/=p; } for(int k=a.size()-1;k>=0;--k) if(a[k]>=10)cout<<char('A'+a[k]-10); else cout<<a[k]; if(j!=i)cout<<' '; } cout<<'\n'; } return 0; }
SMU Winter 2023 Round #3 (Div.2)
思路:当区间个数为偶数,异或和为0,为奇数,为从 l 开始与l奇偶性相同的数的异或和,树状数组分别记录奇数和偶数的异或和
typedef long long LL; const int N = 2e5; int n, m; LL a[N],b[2][N]; int lowbit(int x){ return x&-x; } void add(LL v, int x, int p){ for(int i=x;i<=n;i+=lowbit(i))b[p][i]^=v; } LL Q(int x,int p){ LL ans=0; for(int i=x;i;i-=lowbit(i))ans^=b[p][i]; return ans; } int main() { cin>>n>>m; for(int i=1;i<=n;i++){ cin>>a[i]; add(a[i], i, i & 1); } for(int i=1;i<=m;i++){ int p; LL l,r; cin>>p>>l>>r; if(p==1)add(a[l] ^ r, l, l & 1), a[l]=r; else printf("%lld\n",((l+r)&1)?0:(Q(r,r&1)^Q(l-1,r&1))); } return 0; }
思路:暴力枚举所有情况
int main(){ cin.tie(0),cout.tie(0); int n,m; cin>>m; while(m--){ cin>>n; int a[105],res=0; for(int i=0;i<n;++i) cin>>a[i]; for(int i=0;i<n;++i){ for(int j=i;j<n;++j){ for(int k=j;k<n;++k) if(a[i]+a[j]==a[k])res++; } } cout<<res<<'\n'; } return 0; }
思路:判断结果是否超出范围
int main(){ cin.tie(0),cout.tie(0); int a,b; long long s; cin>>a>>b; s=pow(a,b); if(s>N||s<0)cout<<-1; else cout<<s; return 0; }
思路:统计0~600分数的个数,按照分数线从大开始找
const int N=1e9; int n,w,a[605],x,t; int main(){ cin.tie(0),cout.tie(0); cin>>n>>w; ::memset(a,0,sizeof a); for(int i=1;i<=n;++i){ cin>>x; a[x]++; t=max(1,i*w/100); for(int j=600;j>=0;--j){ if(a[j]!=0) t-=a[j]; if(t<=0){ cout<<j<<' ';break; } } } return 0; }
思路:范围在最边上的四个矩形,判断w,h是否小于等于范围
int main(){ cin.tie(0),cout.tie(0); long long a[2][4],w,h; for(int i=0;i<2;++i) for(int j=0;j<4;++j) cin>>a[i][j]; long long x[4],y[4]; x[0]=abs(a[0][0]-a[1][0]),x[1]=abs(a[0][2]-a[1][2]); y[0]=abs(a[0][3]-a[0][1]),y[1]=abs(a[0][3]-a[0][1]); x[2]=abs(a[0][2]-a[0][0]),y[2]=abs(a[0][1]-a[1][1]); x[3]=abs(a[0][2]-a[0][0]),y[3]=abs(a[0][3]-a[1][3]); cin>>w>>h; for(int i=0;i<4;++i){ if(w<=x[i]&&h<=y[i]){ cout<<"Yes"; return 0; } } cout<<"No"; return 0; }
思路:最后一站人数为0,前一站为2*0+1,依次往前
int main(){ cin.tie(0),cout.tie(0); int t,n; cin>>t; while(t--){ cin>>n; int s=0; while(n--){ s=2*s+1; } cout<<s<<'\n'; } return 0; }
思路:枚举出四个数字的段数
int main(){ cin.tie(0),cout.tie(0); int n,s[10]={6,2,5,5,4,5,6,3,7,6}; cin>>n; for(int i=0;i<3;++i){ for(int j=0;j<=9;++j){ if(i==0&&j==0)continue; if(i==2&&j>3)continue; for(int k=0;k<=5;++k){ for(int t=0;t<=9;++t) if(s[i]+s[j]+s[k]+s[t]==n){ cout<<i<<j<<':'<<k<<t; return 0; } } } } cout<<"Impossible"; return 0; }
思路:01背包
const int N=1e3+5; int f[N],w[105],v[105]; int main(){ cin.tie(0),cout.tie(0); int t,m; cin>>t>>m; for(int i=1;i<=m;++i)cin>>v[i]>>w[i]; for(int i=1;i<=m;++i){ for(int j=t;j>=v[i];--j) f[j]=max(f[j],f[j-v[i]]+w[i]); } cout<<f[t]; return 0; }
思路:欧拉筛将求出范围内素数,反序可能比范围大,定范围时取r的位数的最大值
const int N=1e7; long long l,r,cnt,p[N]; bool st[N]; int main(){ cin.tie(0),cout.tie(0); cin>>l>>r; int a=0,c=r; while(c){ a++; c/=10; } for(int i=2;i<=pow(10,a);++i){ if(!st[i]){ p[cnt++]=i; } for(int j=0;p[j]*i<=pow(10,a);++j){ st[i*p[j]]=true; if(i%p[j]==0)break; } } int x[100000],q=0; for(int i=0;i<cnt;++i){//if(!st[p[i]])cout<<p[i]<<' '; if(p[i]>r)break; if(p[i]>=l){ int t=p[i],k=0; while(t){ k=k*10+t%10; t/=10; } if(!st[k]) x[q++]=p[i]; } } if(q==0){ cout<<"No"; return 0; } for(int i=0;i<q;++i) { cout<<x[i]; if(i<q-1)cout<<','; } return 0; }
思路:求出范围内素数后判断是否满足回文条件
const int N=1e4+10; long long l=11,r,cnt,p[N]; bool st[N]; int main(){ cin.tie(0),cout.tie(0); cin>>r; int a=0,c=r; while(c){ a++; c/=10; } for(int i=2;i<=r;++i){ if(!st[i]){ p[cnt++]=i; } for(int j=0;p[j]*i<=r;++j){ st[i*p[j]]=true; if(i%p[j]==0)break; } } int b[100],k,res=0; for(int i=0;i<cnt;++i){ if(p[i]>=l&&!st[p[i]]){ int t=p[i];k=0; bool ok=true; while(t){ b[k++]=t%10; t/=10; } for(int j=0;j<=(k-1)/2;++j){ if(b[j]!=b[k-1-j]){ ok=false;break; } } if(ok)res++; } } cout<<res; return 0; }
SMU Winter 2023 Round #4 (Div.2)
思路:枚举
int main(){ cin.tie(0),cout.tie(0); int t,x; cin>>t; while(t--){ cin>>x; int res=0; if(x<=12){ for(int i=1;i<=x/2;++i) for(int j=1;j<=6;++j) if(i+j==x){ res++; break; } } cout<<res<<'\n'; } return 0; }
思路:两轮过后锅里没有东西,统计下两轮的周期,再统计剩下的
int main(){ cin.tie(0),cout.tie(0); int t,n,k,m; cin>>t; while(t--){ set<int>se; cin>>n>>k>>m; vector<int>cnt(n,0),a(n); for(int i=0;i<n;++i)cin>>a[i]; int b=m/n,d=m%(2*n); if(b<=1){ for(int i=0;i<m;++i) { int j = i % n; if (se.count(a[j]) == 1) { cnt[j]++; se.erase(a[j]); } else { se.insert(a[j]); } } } else{ for(int i=0;i<2*n;++i){ int j=i%n; if(se.count(a[j])==1){ cnt[j]++;se.erase(a[j]); } else{ se.insert(a[j]); } } for(int i=0;i<n;++i){ cnt[i]*=(b/2); } for(int i=0;i<d;++i){ int j=i%n; if(se.count(a[j])==1){ cnt[j]++;se.erase(a[j]); } else se.insert(a[j]); } } for(int i=0;i<n;++i){ cout<<cnt[i]; if(i!=n-1)cout<<' '; } cout<<'\n'; } return 0; }
Rock Paper Scissors
思路:以后者尽可能多得分来计算
int main(){ cin.tie(0),cout.tie(0); int t; cin>>t; while(t--){ ll a[3],b[3],res=0; for(int i=0;i<3;++i) cin>>a[i]; for(int i=0;i<3;++i) cin>>b[i]; for(int i=0;i<3;++i){ int j=(i-1+3)%3; int mi=min(b[i],a[j]); b[i]-=mi,a[j]-=mi; res+=mi; } for(int i=0;i<3;++i){ int mi=min(a[i],b[i]); a[i]-=mi,b[i]-=mi; } for(int i=0;i<3;++i)res-=a[i]; cout<<res<<'\n'; } return 0; }
思路:每一种对应修改即可
int main(){ cin.tie(0),cout.tie(0); int t; cin>>t; string a[8]={"chimasu","rimasu","mimasu","bimasu","nimasu","kimasu","gimasu","shimasu"}; string b[8]={"tte","tte","nde","nde","nde","ite","ide","shite"}; for(int i=0;i<t;++i){ string c; cin>>c;//cout<<c<<'\n'; for(int j=0;j<8;++j){ int q=c.find(a[j]); if(c=="ikimasu"){ cout<<"itte"<<'\n';break; } if(q!=-1){ c.erase(q,c.size()-1); c+=b[j]; cout<<c<<'\n'; break; } } } return 0; }
思路:从1开始枚举,每次找出+k且小于等于n的数,直到找出n个
int main(){ cin.tie(0),cout.tie(0); int n,k,cnt=0; cin>>n>>k; for(int i=1;i<=n;++i){ for(int j=0;;++j){ if(j*k+i>n)break; cout<<j*k+i; cnt++; if(cnt!=n)cout<<' '; } if(cnt==n)break; } return 0; }
思路:找出最大的登记时间间断,判断每个人能否在最大时间段内到达
int main(){ cin.tie(0),cout.tie(0); ll n,k,x,p0; cin>>n>>k>>x>>p0; vector<double>h(n+5); vector<int> t(k); for(int i=0;i<n;++i){ cin>>h[i]; h[i]=x/h[i]; } for(int i=0;i<k;++i){ cin>>t[i]; } int l,ma=-1; for(int i=0;i<k;++i){ cin>>l; t[i]=l-t[i]; ma=max(ma,t[i]); } int res=0; for(int i=0;i<n;++i){ if(h[i]<=ma)res++; } cout<<res; return 0; }
思路:每2*l的时间,一只蚂蚁可以各撞左右一次后回到原处,且一个2*l的时间内,一边最多撞n次;
可以模拟最后一轮蚂蚁的状态,每次用最后一只撞墙的蚂蚁时间更新撞墙后的蚂蚁的状态,直到没有蚂蚁撞墙,说明所有蚂蚁fall。
or分别算出左右撞碎的时间,若abs(t1-t2)<=l,则ans=max(t1,t2)+l;否则,ans=min(t1,t2)+2*l
#include<bits/stdc++.h> #define int __int128 using namespace std; typedef long long ll; int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=f*-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void write(int x){ if(x>9) write(x/10); putchar(x%10+'0'); } int a[1000005]; int d[10000005]; int tr[1000005]; int tl[1000005]; const int mod=1e9+1; signed main (){ int n,aa,bb; n=read();aa=read();bb=read(); for(int i=1;i<=n;++i) { a[i]=read(); } for(int i=1;i<=n;++i) d[i]=read(); int cnt=0,cnt1=0; tl[0]=0; tr[0]=0; for(int i=1;i<=n;++i) { if(d[i]==0) { tl[++cnt1]=a[i]; } } for(int i=n;i>=1;--i) { if(d[i]==1) { tl[++cnt1]=(2ll*mod-a[i]); tr[++cnt]=(mod-a[i]); } } for(int i=1;i<=n;++i) { if(d[i]==0) { tr[++cnt]=a[i]+mod; } } int nn=n; int rallt,lallt; if(bb%nn!=0) rallt=(bb/(nn))*2ll*mod+tr[(bb-(bb/(nn))*nn)]; else rallt=((bb/(nn))-1)*2ll*mod+tr[nn]; if(aa%nn!=0) lallt=(aa/(nn))*2ll*mod+tl[(aa-(aa/(nn))*nn)]; else lallt=((aa/(nn))-1)*2ll*mod+tl[nn]; int ans=0; if(rallt>=lallt) { if(rallt>=lallt+mod) { ans=lallt+2*mod; } else { ans=rallt+mod; } } else { if(lallt>=rallt+mod) ans=rallt+2*mod; else ans=lallt+mod; } write(ans);putchar('\n'); return 0; }
思路:w的范围小,做100次bfs以点权为wi的所有点作为源点,再更新下每个点权不超过wj的最短路
const int N=1e5+10,inf=0x3f3f3f3f; int n,m,q,w[N],dp[N][105]; vector<int>g[N]; queue<int>qe; void bfs(int x){ for(int i=1;i<=n;++i){ if(w[i]==x){ dp[i][x]=0; qe.push(i); } } while(!qe.empty()){ int u=qe.front();qe.pop(); for(auto v:g[u]){ if(dp[v][x]==inf){ dp[v][x]=dp[u][x]+1; qe.push(v); } } } } int main(){ cin.tie(0),cout.tie(0); memset(dp,0x3f,sizeof dp); cin>>n>>m>>q; for(int i=1;i<=n;++i)cin>>w[i]; while(m--){ int u,v; cin>>u>>v; g[u].emplace_back(v); g[v].emplace_back(u); } for(int i=1;i<=100;++i)bfs(i); for(int i=1;i<=n;++i) for(int j=2;j<=100;++j) dp[i][j]=min(dp[i][j],dp[i][j-1]); while(q--){ int p,t; cin>>p>>t; if(dp[p][t]==inf)cout<<-1<<'\n'; else cout<<dp[p][t]<<'\n'; } }
E - Don't Really Like How The Story Ends
思路:要dfs的序列正好为1~n,当遍历到v时,看是否v+1与v相连,没有则加边,继续访问v+1
const int maxn =100100; int t,n,m,ans,cnt; vector<int>v[maxn]; void dfs(int x){ if(x==n+1)return ; for(auto y:v[x]){ if(y<cnt)continue; while(y>=cnt){ if(y>cnt)ans++; dfs(cnt++); } } } int main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>t; while(t--){ cin>>n>>m; int x,y; for(int i=1;i<=n;++i)v[i].clear(); for(int i=1;i<=m;++i){ cin>>x>>y; v[x].push_back(y),v[y].push_back(x); } v[1].push_back(n+1); for(int i=1;i<=n;++i)sort(v[i].begin(),v[i].end()); ans=0; cnt=2; dfs(1); cout<<ans<<'\n'; } return 0; }
思路:
1.当di<ai时,点i的代价是0;之后没加1,付出的代价就加1
2.(ui,vi)定向后可以恰好让ui和vi中的一个入度加1;考虑用费用流建模来描述过程。费用流图的点集由源点S,汇点T,m个表示原图中边的点A1,...,Am,n个表示原图中点的点B1,...,Bn组成;
3.对于每个Ai,S连接一条边到Ai,费用为0,容量为1;Ai连接两条边到Bui和Bvi,费用均为0,容量均为1;这个过程描述了一条边恰好能使ui和vi中的一个入读加1;
4.对于每个Bi,连接两条边到T;第一条的费用为0,容量为ai;第二条的费用为1,容量为无穷大;费用流增广的过程必定是先增广第一条,再增广第二条,这符合最开始对代价的描述;
5.这个图的最小费用最大流的费用为答案
题意:有一个均匀的三角形薄片 ABC,三个顶点各有一条细线连到一 个点 D 上。给定三边的长度和三条细线的长度,问提起 D 让三 角形自然落下到稳定状态时,三个顶点距离 D 的垂直距离。
思路:二分加贪心
1.二分能够击杀所有怪物的次数,得到每一种伤害使用的次数
贪心:
1)先把3用完:
先把3用在血量大于等于3且血量为奇数的怪物上,使其变成一个偶数且不浪费;
再把3用再血量大于等于6的怪物上(一次要用2个),保证这个怪物的血量还是偶数,且不浪费;
再把3用再血量最多的怪物上;
2)再把2用完:
把2用再血量大于等于2的怪物身上,保证不浪费;
再把2用再血量为1的怪物身上(只剩下1了);
3)最后把1用完;