CF785

A#

题意:

给定一长度为n,由小写字母构成的字符串,a的分数是1b的分数是2,……,z的分数是26AliceBob玩游戏,Alice可以选择长度为偶数的子串删去,Bob可以选择长度为奇数的子串删去,并得到相应的分数。Alice先手,二人轮流操作,谁会赢,赢家比输家最多高多少分?

题解:

特判n=1Bob

否则Alice赢。

如果n是偶数,Alice拿走全部

否则Alice[1n1][2n]中选择分数高的一段。

Copy
#include<bits/stdc++.h> using namespace std; namespace red{ #define int long long #define double long double #define ls(p) (p<<1) #define rs(p) (p<<1|1) #define lowbit(i) ((i)&(-i)) #define mid ((l+r)>>1) #define eps (1e-15) const int N=1e6+10,mod=1e4+7,inf=2e9; int n,m,sum; char s[N]; inline void main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int T;cin>>T; while(T--) { cin>>s; n=strlen(s);sum=0; for(int i=0;i<n;++i) sum+=s[i]-'a'+1; if(n==1) { cout<<"Bob "; cout<<s[0]-'a'+1<<'\n'; continue; } cout<<"Alice "; if(n%2==0) { cout<<sum<<'\n'; } else { sum-=2*min(s[0]-'a'+1,s[n-1]-'a'+1); cout<<sum<<'\n'; } } } } signed main() { red::main(); return 0; } /* */

B#

题意:

给定一字符串,要求满足f(t,u,v),即在字符串的任意子串t中,任选原串出现过的两个字符,都要满足两个这字符在这个子串中出现的个数之差小于等于1。问这个字符串能否满足要求?

题解:

如果字符串要满足要求,这个字符串必须有循环节。而且循环节内不能有重复字符。

Copy
#include<bits/stdc++.h> using namespace std; namespace red{ #define int long long #define double long double #define ls(p) (p<<1) #define rs(p) (p<<1|1) #define lowbit(i) ((i)&(-i)) #define mid ((l+r)>>1) #define eps (1e-15) const int N=1e6+10,mod=1e4+7,inf=2e9; int n,m; char s[N]; int col; map<int,int> q; inline void main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int T;cin>>T; while(T--) { cin>>s;n=strlen(s); q.clear(); int len=0; bool flag=0; for(int i=0;i<n;++i) { if(q[s[i]]) { if(q[s[i]]!=1) flag=1; len=i; break; } q[s[i]]=1; } for(int i=0;i<len;++i) { int j=i; while(j<n) { if(s[i]!=s[j]) flag=1; j+=len; } } if(flag) cout<<"NO\n"; else cout<<"YES\n"; } } } signed main() { red::main(); return 0; } /* */

C#

题意:

问一个数字n(1n4104)有几种拆分成回文数字相加的方法,比如121是回文数字。

题解:

打个表发现40000以内的回文数只有500

dp[i][j]表示数字i,只用大于等于第j个回文数来拆分,得到的方案数,做个后缀和就可以O(1)转移了。

Copy
#include<bits/stdc++.h> using namespace std; namespace red{ #define int long long #define double long double #define ls(p) (p<<1) #define rs(p) (p<<1|1) #define lowbit(i) ((i)&(-i)) #define mid ((l+r)>>1) #define eps (1e-15) const int N=40000+10,mod=1e9+7,inf=2e9; int n,m; int f[N]; int st[N],top; int g[N],num; int dp[N][501]; inline bool check(int x) { int y=x; top=0; while(x) st[++top]=x%10,x/=10; int z=0; for(int i=1;i<=top;++i) z=z*10+st[i]; return (z==y); } inline void main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int T;cin>>T; for(int j=0;j<=500;++j) dp[0][j]=1; for(int i=1;i<=40000;++i) { if(check(i)) { g[++num]=i; } for(int j=1;j<=num;++j) { dp[i][j]=dp[i-g[j]][j]; } for(int j=num;j>=1;--j) dp[i][j]=(dp[i][j]+dp[i][j+1])%mod; } while(T--) { cin>>n; cout<<dp[n][1]<<'\n'; } } } signed main() { red::main(); return 0; } /* */

D#

题意:

已知等差数列C是等差数列A,B的所有公共项,问有多少种可能的等差数列A

题解:

第一步是判断C是不是B的真正的子序列。

判断方法是,C的首项和尾项有没有在B中出现过,C的公差是不是B的倍数。

第二步判断是不是有无限种,方法是看C首项的前一项和尾项的后一项有没有在B中出现过。

最后一步是计算种类数

A的公差只可能是C的因子,因此只要枚举A的公差,同时A,B公差的最小公倍数必须是C的公差,否则它们两个就会在C相邻两项之间相交。

A的可能的种类数就是C首尾之外的发散项,其实就是C的首项到上一项之间。

Copy
#include<bits/stdc++.h> using namespace std; namespace red{ #define int long long #define double long double #define ls(p) (p<<1) #define rs(p) (p<<1|1) #define lowbit(i) ((i)&(-i)) #define mid ((l+r)>>1) #define eps (1e-15) const int N=1e6+10,mod=1e9+7,inf=2e9; int n,m,ans; int a0,b0,c0,q1,q2,q3; inline bool checkbc() { int s=b0; int l=0,r=n-1,k=0; while(l<=r) { if(s+mid*q2<=c0) k=mid,l=mid+1; else r=mid-1; } if(s+k*q2!=c0) return 0; l=0,r=n-1,k=n-1; while(l<=r) { if(s+mid*q2>=c0+(m-1)*q3) k=mid,r=mid-1; else l=mid+1; } if(s+k*q2!=c0+(m-1)*q3) return 0; if(q3%q2!=0) return 0; return 1; } inline int lcm(int x,int y) { return x*y/__gcd(x,y); } inline void work(int l,int r,int tl,int tr,int x) { // cout<<x<<"!!"<<endl; //cout<<tl<<' '<<l<<"!!!"<<endl; int k=(tl-l)/x; //cout<<x<<' '<<k<<"!!"<<endl; ans=(ans+k*k)%mod; } inline void main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int T;cin>>T; while(T--) { cin>>b0>>q2>>n; cin>>c0>>q3>>m; ans=0; if(!checkbc()||c0<b0||(c0+(m-1)*q3)>(b0+(n-1)*q2)) { cout<<"0"<<'\n'; continue; } if(c0-q3<b0||(c0+m*q3)>(b0+(n-1)*q2)) { cout<<"-1\n"; continue; } //ans=1; for(int q1=1;q1*q1<=q3;++q1) { if(q3%q1!=0) continue; int x=q1,y=lcm(x,q2); if(y==q3) work(c0-q3,c0+m*q3,c0,c0+(m-1)*q3,x); if(q1*q1==q3) continue; x=q3/q1,y=lcm(x,q2); //if(x==q3) cout<<y<<' '<<q3<<"!!!!!!!!!!!!!"<<endl; if(y==q3) work(c0-q3,c0+m*q3,c0,c0+(m-1)*q3,x); } cout<<ans<<'\n'; } } } signed main() { red::main(); return 0; } /* 1 -685761754 232786464 375044871 -220188826 232786464 262040392 */

E#

给定序列B(1bi<220),长度为n(1n220),真实序列是Ai=2Bi

E=A1A2An

现在要给每个设计一个意义,要么是异或,要么是幂次,幂次的运算优先级高于异或。

至少要把m设计乘异或。

求所有可能的设计方案的E的值的异或和,以二进制形式输出,答案对2220取模。

题解:

由于幂次优先级高于异或,所以等于是通过异或符号把序列分隔成至少m+1段。这可以用隔板法解决。

每一段之间都是幂次运算,运算结果都是二的整幂次。

可以直接哪一段作为未分割的一段,计算这段的出现次数。

可以发现,bi>=1,也就是说这个长度不会超过20,否则就会被模掉。

而且在隔板法中,把n个数分成至少m段也只会有20种不同的n,m,所以可以算组合数。

但是这种级别的组合数没有模数很难搞定,好在只需要知道奇偶性,所以设计s[i]表示i!中乘过多少个2

Copy
#include<bits/stdc++.h> using namespace std; namespace red{ #define int long long #define double long double #define ls(p) (p<<1) #define rs(p) (p<<1|1) #define lowbit(i) ((i)&(-i)) #define mid ((l+r)>>1) #define eps (1e-15) const int N=2e6+10,mod=(1<<20),inf=2e9; int n,m; int b[N]; int s[N]; int ans[N]; inline int C(int n,int m) { if(n<m) return 0; int s1=s[n],s2=s[n-m]+s[m]; if(s1>s2) return 0; return 1; } typedef pair<int,int> pr; map<pr,int> q; inline int work(int n,int m) { m=max(0ll,m); if(n<m) return 0; //cout<<n<<' '<<m<<"!!!!!!!!"<<endl; if(q[pr(n,m)]) return q[pr(n,m)]; int s=0; for(int k=m;k<=n;++k) s+=C(n,k); if(s%2==0) s=2; else s=1; return (q[pr(n,m)]=s); } inline void main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); cin>>n>>m;++m; for(int i=2;i<=n;i*=2) { for(int j=1;i*j<=n;++j) { ++s[i*j]; } } for(int i=1;i<=n;++i) s[i]+=s[i-1]; for(int i=1;i<=n;++i) { cin>>b[i]; } for(int l=1;l<=n;++l) { int r=l,k=b[l]; while(k<mod) { int tmp=work(n-1-(r-l+2)+(l==1)+(r==n),m-1-2+(l==1)+(r==n)); //if(r-l+1==3)cout<<l<<' '<<r<<' '<<tmp<<"!!"<<endl; //cout<<n-1-(r-l+2)+2*(l==1)+2*(r==n)<<' '<<m-1-2+2*(l==1)+2*(r==n)<<' '<<k<<"!!!"<<endl; if(tmp%2==1) ans[k]^=1; ++r; if(b[r]>=20||r>n) break; int op=(1<<b[r]); k*=op; } } bool flag=0; for(int i=mod-1;i>=0;--i) { if(ans[i]==1||i==0) flag=1; if(flag) cout<<ans[i]; } cout<<'\n'; } } signed main() { red::main(); return 0; } /* 10 3 1 1 1 1 1 1 1 1 1 1 */

F#

题意:

给定nn(2n32)的网格,给每条边一个权值,总和不能超过48000

有一个小偷从(1,1),陆续偷盗m个地点,他每经过一条边,一个计数器就会让数字异或上这条边的长度,偷完之后会输出数字并清空计数器。

现在你要给每条边安排一个权值,然后每次计数器会给你一个数字,根据这个数字判断出小偷偷走了哪个坐标的物品。

题解:

有很多种方法设计权值,但是要总和不超过48000很难。

考虑一种从02k1唯一分布的数码格雷码,因为格雷码有一个特点,最零位翻转2k1次,第一位翻转2k2次……最高位翻转1次,也就是说越低位在异或时,出现次数越多,刚好可以最小化路径总长度。

二维格雷码可以简化,将g(i)2设计为横向边权,将2g(i)2设计为纵向边权,总和刚好小于48000

Copy
#include<bits/stdc++.h> using namespace std; namespace red{ #define int long long #define double long double #define ls(p) (p<<1) #define rs(p) (p<<1|1) #define lowbit(i) ((i)&(-i)) #define mid ((l+r)>>1) #define eps (1e-15) const int N=35,mod=1e4+7,inf=2e9; int n,m,k; int a[N][N],b[N][N]; int ansx[N][N],ansy[N][N]; int stx,sty; inline int pow(int n) { int x=1; while(n%2==0) { x<<=1; n>>=1; } return x; } inline void main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int T=1; while(T--) { cin>>n>>m;int sum=0; for(int i=1;i<=n;++i) { for(int j=1;j<n;++j) { a[i][j]=pow(j)*pow(j); ansx[i][j+1]=ansx[i][j]^a[i][j]; sum+=a[i][j]; } } for(int j=1;j<=n;++j) { for(int i=1;i<n;++i) { b[i][j]=2*pow(i)*pow(i); ansy[i+1][j]=ansy[i][j]^b[i][j]; sum+=b[i][j]; } } for(int i=1;i<=n;++i) { for(int j=1;j<n;++j) { cout<<a[i][j]; if(j==n-1) cout<<endl; else cout<<' '; } } for(int i=1;i<n;++i) { for(int j=1;j<=n;++j) { cout<<b[i][j]; if(j==n) cout<<endl; else cout<<' '; } } //cout<<sum<<"!!!"<<endl; stx=sty=1; //cout<<ansy[1][2]<<' '<<ansy[2][2]<<"!!"<<endl; while(m--) { int x;cin>>x; bool flag=0; for(int i=1;i<=n&&!flag;++i) { for(int j=1;j<=n&&!flag;++j) { int l=sty,r=j; if(l>r) swap(l,r); int tmp=ansx[i][l]^ansx[i][r]; l=stx,r=i; if(l>r) swap(l,r); tmp^=ansy[l][j]^ansy[r][j]; //cout<<stx<<' '<<sty<<' '<<i<<' '<<j<<' '<<tmp<<"!!"<<endl; if(tmp==x) { flag=1; stx=i,sty=j; cout<<i<<' '<<j<<endl; break; } } } } } } } signed main() { red::main(); return 0; } /* */
posted @   lovelyred  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示
CONTENTS