http://codeforces.com/contest/710
A:水题
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define fi first #define se second #define mp make_pair #define pb push_back #define pi acos(-1.0) #define ll long long #define mod 1000000007 #define C 0.5772156649 #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 #define pil pair<int,ll> #define pii pair<int,int> #define ull unsigned long long #define base 1000000000000000000 #define fio ios::sync_with_stdio(false);cin.tie(0) using namespace std; const double g=10.0,eps=1e-12; const int N=300000+10,maxn=400000+10,inf=0x3f3f3f3f; int main() { fio; string s; cin>>s; if(s[0]=='a'||s[0]=='h') { if(s[1]=='8'||s[1]=='1')puts("3"); else puts("5"); } else { if(s[1]=='8'||s[1]=='1')puts("5"); else puts("8"); } return 0; } /******************** ********************/
B:找规律题,当时一直以为是三分,所以一直wa。。。。
题意:一堆数,找x使得x和他们的距离差的和最小
首先不可能在两端,当x在两个点之间时,我们可以列出距离的公式,显然他是一元一次方程,肯定单调,所以在两端取,前后缀维护一下即可,但是我看别人都是第二种,虽然直觉上确实是对的,但是我也不会严格证明
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define fi first #define se second #define mp make_pair #define pb push_back #define pi acos(-1.0) #define ll long long #define mod 1000000007 #define C 0.5772156649 #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 #define pil pair<int,ll> #define pii pair<int,int> #define ull unsigned long long #define base 1000000000000000000 #define fio ios::sync_with_stdio(false);cin.tie(0) using namespace std; const double g=10.0,eps=1e-12; const int N=300000+10,maxn=400000+10,inf=0x3f3f3f3f; ll a[N],sum1[N],sum2[N]; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%lld",&a[i]); sort(a+1,a+1+n); for(int i=1;i<=n;i++)sum1[i]=sum1[i-1]+a[i]; for(int i=n;i>=1;i--)sum2[i]=sum2[i+1]+a[i]; ll ans=1e18,id; for(int i=1;i<=n;i++) { ll te=sum2[i+1]-a[i]*(n-i)+a[i]*(i-1)-sum1[i-1]; if(ans>te) { ans=te; id=a[i]; } } printf("%lld ",id); return 0; } /******************** ********************/
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define fi first #define se second #define mp make_pair #define pb push_back #define pi acos(-1.0) #define ll long long #define mod 1000000007 #define C 0.5772156649 #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 #define pil pair<int,ll> #define pii pair<int,int> #define ull unsigned long long #define base 1000000000000000000 #define fio ios::sync_with_stdio(false);cin.tie(0) using namespace std; const double g=10.0,eps=1e-12; const int N=300000+10,maxn=400000+10,inf=0x3f3f3f3f; ll a[N],sum1[N],sum2[N]; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%lld",&a[i]); sort(a+1,a+1+n); printf("%lld ",a[(n+1)/2]); return 0; } /******************** ********************/
C:题意:给你一个奇数n,让你构造一个n*n矩阵要求填的数只能是1到n*n,每个格子不同,每行每列以及主副对角线和都必须是奇数
解法:我们先1到n*n顺序填,填完之后会发现有一些圈是不满足的,比如
1 2 3
4 5 6
7 8 9
那么我们把最外圈平移一格变成了
2 3 6
1 5 9
4 7 8,这样就能满足条件了,以此类推3,7,11....都需要旋转
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define fi first #define se second #define mp make_pair #define pb push_back #define pi acos(-1.0) #define ll long long #define mod 1000000007 #define C 0.5772156649 #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 #define pil pair<int,ll> #define pii pair<int,int> #define ull unsigned long long #define base 1000000000000000000 #define fio ios::sync_with_stdio(false);cin.tie(0) using namespace std; const double g=10.0,eps=1e-12; const int N=100+10,maxn=400000+10,inf=0x3f3f3f3f; int ans[N][N]; int main() { int n; scanf("%d",&n); int num=1; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) ans[i][j]=num++; // for(int i=1;i<=n;i++) // { // for(int j=1;j<=n;j++) // printf("%2d ",ans[i][j]); // puts(""); // } for(int i=3;i<=n;i+=4) { int p=(n+i)/2; vector<int>v; for(int j=n-p+1;j<=p;j++) v.pb(ans[n-p+1][j]); for(int j=n-p+2;j<=p;j++) v.pb(ans[j][p]); for(int j=p-1;j>=n-p+1;j--) v.pb(ans[p][j]); for(int j=p-1;j>=n-p+2;j--) v.pb(ans[j][n-p+1]); // for(int j=0;j<v.size();j++) // printf("%d ",v[j]); // puts(""); int cnt=1; for(int j=n-p+1;j<=p;j++) ans[n-p+1][j]=v[cnt++]; for(int j=n-p+2;j<=p;j++) ans[j][p]=v[cnt++]; for(int j=p-1;j>=n-p+1;j--) ans[p][j]=v[cnt++]; for(int j=p-1;j>=n-p+2;j--) { if(cnt==v.size())cnt=0; ans[j][n-p+1]=v[cnt++]; } } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) printf("%2d ",ans[i][j]); puts(""); } return 0; } /******************** 1010101 0101010 1010101 0101010 1010101 0101010 1010101 ********************/
D:给你a1,a2,b1,b2,l,r,要求找到在lr之间的x,满足x=a1*k+b1=a2*l+b2,kl必须大于0
解法:扩展中国剩余定理,中国剩余定理是对于y=a1*x+b1=a2*x+b2
变形一下a1*x+a2*y=b2-b1;,我们可以用扩展gcd来求这个方程的解,
扩展gcd:对于直接套exgcd的x,y是a*x+b*y=gcd(a,b)的解,对于原方程的解我们需要乘上c/gcd(a,b),那么我们得到了一个特解x0,通解x=x0+k*b/gcd(a,b)
那么我们再回到中国剩余定理上,将exgcd求得的通解x带入y=a1*x+b1,就得到了通解y,y%lcm(a1,a2)又等于0,
对于这题来说,我们找到了通解y,但是需要在l,r之间,而且满足k,l为正数,当然我们可以将区间缩小到(max(l,max(b1,b2)),r)这样就满足了 kl>=0,我们将特解减到比l小的地方,然后加上r到y,减去l到y
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define fi first #define se second #define mp make_pair #define pb push_back #define pi acos(-1.0) #define ll long long #define mod 1000000007 #define C 0.5772156649 #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 #define pil pair<int,ll> #define pii pair<ll,int> #define ull unsigned long long #define base 1000000000000000000 #define fio ios::sync_with_stdio(false);cin.tie(0) using namespace std; const double g=10.0,eps=1e-12; const int N=20000+10,maxn=90000+10,inf=0x3f3f3f3f; ll exgcd(ll a,ll b,ll &x,ll &y) { if(!b) { x=1,y=0; return a; } ll ans=exgcd(b,a%b,x,y); ll t=x;x=y;y=t-a/b*y; return ans; } int main() { ll a1,a2,b1,b2,l,r; scanf("%lld%lld%lld%lld%lld%lld",&a1,&b1,&a2,&b2,&l,&r); ll a=a1,b=a2,c=b2-b1,x,y; ll d=exgcd(a,b,x,y); ll lcm=a/__gcd(a,b)*b; l=max(l,max(b1,b2)); x*=c/__gcd(a,b); if(c%d!=0||l>r)puts("0"); else { ll t=b/__gcd(a,b); x=(x%t+t)%t;//min position solution x=a1*x%lcm+b1; x%=lcm; if(l>0)x-=lcm; else x+=(int)(l/lcm-2)*lcm; ll ans=0; // printf("%lld ",ans); // printf("%lld %lld %lld %lld %lld %lld ",x,l,r,lcm,l%lcm,r%lcm); if(x<=r)ans+=(r-x)/lcm; if(x<=l-1)ans-=(l-1-x)/lcm; printf("%lld ",ans); } return 0; } /******************** 4 2963 394 577593 125523962 628140505 ********************/
E:两种操作一种把a个数+1或者-1,代价是x,一种是把a翻倍,代价是y,求a个数从0到n的最小代价
解法:dp【i】表示从i到n所需的最小代价,当i为奇数dp只能从dp【i-1】或者dp【(i+1)/2】转移过来,因为更大的i+x转移过来和i+1是一样的,当i是偶数,dp【i】只能是dp【i/2】或者dp【i-1】转移,
转移方程if(i&1) dp[i]=min(dp[i-1]+x, dp[(i +1) >> 1] + x + y);else dp[i]=min(dp[i/2]+y,dp[i-1]+x);
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define fi first #define se second #define mp make_pair #define pb push_back #define pi acos(-1.0) #define ll long long #define mod 1000000007 #define C 0.5772156649 #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 #define pil pair<int,ll> #define pii pair<ll,int> #define ull unsigned long long #define base 1000000000000000000 #define fio ios::sync_with_stdio(false);cin.tie(0) using namespace std; const double g=10.0,eps=1e-12; const int N=20000000+10,maxn=90000+10,inf=0x3f3f3f3f; ll dp[N]; int main() { ll n,x,y; scanf("%lld%lld%lld",&n,&x,&y); for(int i=1;i<=n;i++) if(i&1) dp[i]=min(dp[i-1]+x, dp[(i +1) >> 1] + x + y); else dp[i]=min(dp[i/2]+y,dp[i-1]+x); printf("%lld ",dp[n]); return 0; } /******************** ********************/
F:题意:三种操作,一种加一个字符串到集合中(保证不相同)一种删除某个字符串(保证一定存在),一种查询集合中的字符串在给定的字符串中出现过几次(重合的也算)
解法:考虑建多个ac自动机,但是建n个ac自动机肯定是会mle的,我们可以用二进制分组
二进制分组:例如21=16+4+1,当21+1时,22=16+4+1+1=16+4+2保证每一位是2的幂次,那么对于每次加,最多只可能有logn个操作,查询也变成了logn个操作,这样就比直接暴力的n^2快多了,复杂度是nlognlogn
现在我们建logn个ac自动机,每次加入时像二进制分组这样合并两个ac自动机,合并我们可以直接暴力删掉,然后暴力重新建图,建立fail指针
对于删除操作我们考虑建两个ac自动机,然后一个代表+,一个代表-,最后的结果就是第一个-第二个
然后这题的数据比较水,所有字符串hash也能过,附上字符串hash的代码(ac自动机的代码懒得写了= =)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define fi first #define se second #define mp make_pair #define pb push_back #define pi acos(-1.0) #define ll long long #define mod 1000000007 #define C 0.5772156649 #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 #define pil pair<int,ll> #define pii pair<int,int> #define ull unsigned long long #define base 1000000000000000000 #define fio ios::sync_with_stdio(false);cin.tie(0) using namespace std; const double g=10.0,eps=1e-12; const int N=300000+10,maxn=400000+10,inf=0x3f3f3f3f; const ll bs=199; map<int,set<int> >m; int Hash[N]; int ha(char *s) { int ans=0,len=strlen(s); for(int i=0;i<len;i++) ans=(bs*ans+s[i])%mod; return ans; } int query(char *s) { int ans=0,v=ha(s),len=strlen(s); for(auto x=m.begin();x!=m.end()&&x->fi<=len;x++) { int res=0; for(register int i=0;i<x->fi;i++) res=(bs*res+s[i])%mod; if(x->se.find(res)!=x->se.end())ans++; for(int i=0;i+x->fi<len;i++) { res=(bs*res+s[i+x->fi]-(ll)Hash[x->fi]*s[i])%mod+mod; if(res>mod)res-=mod; if(x->se.find(res)!=x->se.end())ans++; } } return ans; } char s[N]; int main() { int n;scanf("%d",&n); Hash[0]=1; for(int i=1;i<N;i++) Hash[i]=bs*Hash[i-1]%mod; for(register int i=0;i<n;i++) { int op; scanf("%d%s",&op,s); if(op==1) { int len=strlen(s); m[len].insert(ha(s)); } else if(op==2) { int len=strlen(s); m[len].erase(ha(s)); if(m[len].size()==0)m.erase(len); } else { printf("%d ",query(s)); fflush(stdout); } } return 0; } /******************** ********************/