J 找规律

一开始思路错了,光看给的图以为x取整数点,y在整数之间就算超过一半了,忽略了另一个交正方形的点,反例如a=1,b=999
所以x看的是0.5处的点,可以把坐标轴*2避免使用double
cpp
void solve(){
int na,nb;cin>>na>>nb;
int a=max(na,nb),b=min(na,nb);
int sm=0;
for(int i=1;i<=2*a;i+=2){
int hd=4*b*a-2*b*i;
int top=hd/(2*a);
// cout<<top<<' ';
sm+=(top+1)/2;
}
cout<<sm<<endl;
}
M 题意理解

只要被按下,就会触发后面一连串的操作
如果这个按下是被触发的,也会触发对应的一连串
所以按下1后触发的小连招包含x,结束后再主动按x,又会和之前的连招抵消。所以只有1是开的
D 枚举 调和奇数 正难则反 等差数列

等差数列需要确定首相 a 1 a_1 a1和公差 k k k,枚举然后遍历找答案必然超时
遍历找要改的数很浪费,正难则反,确定不用改的数。最小花多少就等于最大省多少。
枚举每个位置为不变,枚举公差k,从 a i ≤ 10 6 a_i\leq 10^6 ai≤106, k ≤ a i i − 1 ≤ 10 6 i − 1 k\leq \frac{a_i}{i-1}\leq \frac{10^6}{i-1} k≤i−1ai≤i−1106,由调和级数k总共最多枚举 10 6 l o g n ≈ 2 e 7 10^6logn\approx 2e7 106logn≈2e7
cpp
void solve(){
int n;cin>>n;
vector<int>a(n+1),b(n+1);
forr(i,1,n)cin>>a[i];
int bsm=0;
forr(i,1,n)cin>>b[i],bsm+=b[i];
map<pii,int>match;
forr(i,1,n){
forr(k,0,(1e6/i)){
int a1=a[i]-(i-1)*k;
if(a1>=0){
match[{a1,k}]+=b[i];
}
}
}
int mx=0;
for(auto [k,v]:match){
mx=max(mx,v);
}
cout<<bsm-mx<<endl;
}
F 博弈

看到样例可以猜一手跟奇偶性有关
发现每位最后一个操作的必能把这一位变成自己想要的数(拿到这一位)
cpp
void solve(){
int k,z;
cin>>k>>z;
vector<int>b(k+1),ans(k+1,0);
vector<int>cnt1;// 记录b=1的地方 AB两人轮流取
int c=0,c1=0;// c是b>=2的b位奇数个数 c1是b=1的个数
forr(i,0,k-1){
cin>>b[i];
if(b[i]==1){
cnt1.push_back(i);
c1++;
}else if(b[i]==0)ans[i]=0;
else if(b[i]&1){
c++;
}
}
/*
c1:
- 奇数:取完b=1之后B先手
- 偶数:之后A先手
z:
- 奇:改变先后手
- 偶:不变
c:
- 偶:后手一直演先手,能保证奇数个每个位置都是后手最后拿捏,偶数个部分先手先拿,后手最后拿
后手都能拿到
- 奇:先手比后手多一个,能取到最后拿捏的位置;偶数个部分后手先拿
先手都能拿到
*/
sort(cnt1.begin(),cnt1.end(),greater<int>());
forr(i,0,c1-1){
if(i%2==0)ans[cnt1[i]]=1;// b=1 AB一轮轮争抢
}
if((c1+c+z)%2){// 三者之和为奇 A最后一个操作 所有b>=2的都能拿到
forr(i,0,k-1)if(b[i]>=2)ans[i]=1;
}
reforr(i,0,k-1)cout<<ans[i];cout<<endl;
}
L 状压 哈希

暴力规模能达到1e10,超时
因为s长度只有5,可以状压枚举每个位置是否匹配,然后记录每个状态的字符串情况,告诉的和询问的进行匹配,找最大相似度的最小编号
但是用map记录字符串会TLE(退化到了O(n)),使用字符串哈希记录数值
cpp
// unordered_map<string,int>rec; TLE
vector<int>rec(N,inf);// int最大能开536698431
// vector<string>c_vec[25][6];
// int similar(string a,string b){
// int res=0;
// forr(i,0,min(a.size(),b.size())-1){
// if(a[i]!=b[i])break;
// else res++;
// }
// return res;
// }
void solve(){
int q;cin>>q;
/* 暴力
forr(i,1,q){
int op;cin>>op;
if(op==1){
string s;int x;
cin>>s>>x;
rec[s]=x;
}else {
string s;
cin>>s;
int mx=0;string aim;
for(auto [ss,v]:rec){// 1e5*1e5超时
int now=similar(ss,s);
if(now>mx)aim=ss,mx=now;
}
}
}
*/
forr(i,1,q){
int op;cin>>op;
if(op==1){
/*
利用|s|=5 枚举可能的匹配情况 量化匹配度 状压
*/
string s;int x;
cin>>s>>x;
/*
forr(i,0,31){
string now;// 用字符串匹配会TLE 所以使用vector存hash值
forr(j,0,s.size()-1){
// 1:匹配 0:不匹配
if((i>>j)&1){
now+=s[j];
}else now+='#';
}
if(!rec[now]||rec[now]>x)rec[now]=x;// 记录固定匹配度 最小编号
}
*/
forr(i,0,31){
int val=0,p=1;
forr(j,0,s.size()-1){
// 1:匹配 0:不匹配
int now=((i>>j)&1)*(s[j]-'a'+1);// a~z 1~26
val+=now*p;
p*=27;
}
rec[val]=min(rec[val],x);
}
}else {
string s;
cin>>s;
// int sim_mx=0,ans=1;
int sim_mx=-1,ans=1;// sim_mx可能最后最大为0
/*
forr(i,0,31){
string now;
int sim=0;
forr(j,0,s.size()-1){
// 1:匹配 0:不匹配
if((i>>j)&1){
now+=s[j];
sim++;
}else now+='#';
}
if(sim>sim_mx&&rec.count(now))ans=rec[now];
}
*/
forr(i,0,31){
int sim=0,val=0,p=1;
forr(j,0,s.size()-1){
int now=((i>>j)&1)*(s[j]-'a'+1);
val+=now*p;
p*=27;
sim+=((i>>j)&1);
}
if(rec[val]!=inf){
if(sim>sim_mx)ans=rec[val],sim_mx=sim;
else if(sim==sim_mx)ans=min(ans,rec[val]);// 找同匹配数下更小的
}
}
cout<<ans<<endl;
}
}
}