B.https://www.codechef.com/problems/STROPR
题意:将数列{x1,x2,..,xn}进行前缀累加操作,得到{s1,s2,..,sn},求这样操作k次后数列中第m个值。
画出每次操作后第m个数所包含初始数列{x1,x2,..,xn}里每个数的个数:
.... m-2 m-1 m ← m
1 1 1 1 1 1 1
6 5 4 3 2 1 k↓ 2
21 15 10 6 3 1 3
56 35 20 10 4 1 4
观察每行从右往左[1,2,3,4],[1,3,6,10],[1,4,10,20],[1,5,10,15],[1,6,21,66]的规律,发现是n*(n+1)*(n+2)*(n+k-1)/k!,k是从上往下第几层。
于是求【第k行第m个】的问题转化成了求【前m个数分别乘上对应上表k行前m个数】
我晕。。明明在zju那时可以迅速想到的,这次用到这个公式的时候反应竟然奇慢无比,一直在想n*a1+n*(n+1)/2!*a2+n*(n+1)*(n+2)/3!*a3+...以累乘的方式求解又会导致除法取模错误
以后记住:碰到类似这种n*(n+1)*(n+2)*...*(n+m-1)/m!务必第一时间想到组合公式C(n+m-1,m)
————————————————————————————————————————————
但这题的mod是1000000007(太大了),用lucas不幸死在超时。所以上述方法本题不适用!正解是老老实实手动逆元打表(这居然是第二题该有的做法?!)所以,,非常有用的逆元模板。
#include<bits/stdc++.h> #define ll long long #define maxn 10000005 #define mod 1000000007 #define eps 1e-12 using namespace std; ll x[100005]; //【求逆元】模板 ll inverseFactorial[maxn+1]; ll inverseModulo(int b) //b的逆元 { ll x = 0, y = 1, r, q; int a = mod; while(b){ q = a/b; r = a%b; a = b; b = r; r = x; x = y; y = r - q * y; } if(x < 0) x += mod; return x; } void factorialInv(void) //求阶乘n!的逆元 { ll ret = 1; inverseFactorial[0]=ret; for(int i = 1; i < maxn; i++) { ret = ret * inverseModulo(i) % mod; inverseFactorial[i]=ret; } } int main(){ factorialInv(); int t; scanf("%d",&t); while(t--){ int n,m; ll k; scanf("%d%d%lld",&n,&m,&k); k%=mod; // cin>>n>>m>>k; for(int i=1;i<=n;++i){ scanf("%lld",&x[n-i+1]); x[n-i+1]%=mod; } m=n-m+1; ll s=0,ret=1,h=k; for(int i=m;i<=n;++i){ s=(s+ret*inverseFactorial[i-m]%mod*x[i]%mod)%mod; ret=(ret*h)%mod; h=(h+1)%mod; } printf("%lld\n",s); } return 0; }
#include<bits/stdc++.h> #define ll long long #define maxn 10000005 #define mod 1000000007 #define eps 1e-12 using namespace std; ll PowMod(ll a,ll b,ll MOD){ ll ret=1; while(b){ if(b&1) ret=(ret*a)%MOD; a=(a*a)%MOD; b>>=1; } return ret; } ll fac[maxn]; ll Get_Fact(ll p){ fac[0]=1; for(int i=1;i<=p;i++) //超时是因为这里的p fac[i]=(fac[i-1]*i)%p; } ll Lucas(ll n,ll m,ll p){ ll ret=1; while(n&&m){ ll a=n%p,b=m%p; if(a<b) return 0; ret=(ret*fac[a]*PowMod(fac[b]*fac[a-b]%p,p-2,p))%p; n/=p; m/=p; } return ret; } //Lucas(n,m,mod) ll x[100005]; int main(){ Get_Fact(mod); int t; scanf("%d",&t); while(t--){ int n,m; ll k; scanf("%d%d%lld",&n,&m,&k); // cin>>n>>m>>k; m--; m=n-m-1; for(int i=0;i<n;++i){ scanf("%lld",&x[n-i-1]); x[n-i-1]%=mod; } ll s=0; for(int i=m;i<n;++i){ //本来是需要k--的,但由于123对应的111是初始状态不计在列,往后顺延抵消 int p=i-m; s=(s+Lucas(k+p-1,p,mod)*x[i]%mod)%mod; } printf("%lld\n",s); } return 0; }
E.https://www.codechef.com/FEB16/problems/SEATL
数据范围和子任务
• 1 ≤ 每组数据中 N × M 之和 ≤ 10^6
• 1 ≤ Ai,j ≤ 10^6
AC的代码各种千奇百怪的做法:二分,归并排序,BFS,各种神思路。。。
而我尝试用map各种超时。。。
满脑子想的是比较所有十字形里所有数的次数,也就是常规做法。除此以外我想到的都是我认为超时的做法。不得不说某大神的做法很巧妙。好题。
再想一遍...再写一遍...
#include<bits/stdc++.h> #define ll long long using namespace std; int x[1000005]; int f[1000005]; int vis[1000005]; int row[1000005]; int col[1000005]; vector<pair<int,int> > v[1000005]; map<int,int> r; int main(){ int t; scanf("%d",&t); while(t--){ // memset(vis,0,sizeof(vis)); int n,m,a; scanf("%d%d",&n,&m); int c=-1; for(int i=1;i<=n;++i){ for(int j=1;j<=m;++j){ scanf("%d",&a); if(vis[a]==0) f[++c]=a; vis[a]=1; v[a].push_back({i,j}); } } int maxx=0; for(int i=0;i<=c;++i){ int p=f[i]; //出现过的数字 int maxr=0,maxc=0,s1=1,s2=1; for(int j=0;j<v[p].size();++j){ //遍历这个数出现过的所有位置(两个for刚好O(n*m)) row[v[p][j].first]++; //在哪一行出现过,该行次数+1 col[v[p][j].second]++; //在哪一列出现过,该列次数+1 if(row[v[p][j].first]>maxr){ maxr=row[v[p][j].first]; s1=1; } else if(row[v[p][j].first]==maxr) s1++; //出现次数最多的行有几个 if(col[v[p][j].second]>maxc){ maxc=col[v[p][j].second]; s2=1; } else if(col[v[p][j].second]==maxc) s2++; //出现次数最多的列有几个 } int s=s1*s2; //此乃画龙点睛之处 for(int j=0;j<v[p].size();++j){ int a=v[p][j].first,b=v[p][j].second; if(row[a]==maxr&&col[b]==maxc) //这个点位于某个【行列都最多】的十字交叉上 s--; } if(s>0) maxx=max(maxx,maxr+maxc); else maxx=max(maxx,maxr+maxc-1); for(int j=0;j<v[p].size();++j){ //恢复这两个数组的原貌(每次结束都归零) row[v[p][j].first]--; col[v[p][j].second]--; } v[p].clear(); vis[p]=0; } printf("%d\n",maxx); } }
F.https://www.codechef.com/FEB16/problems/MTMXSUM
这题的做法我暂时不是很理解。。。
#include <bits/stdc++.h> using namespace std; #define pb push_back #define mp make_pair #define REP(i,n)for (int i=0;i<(int)(n);++i) typedef long long LL; typedef pair<int,int> PII; int n; int a[100000],b[100000]; const int MOD=1e9+7; int le[100000],ri[100000],aa[100003]={},bb[100003]={}; inline void modAdd(int &x,int y){ x+=y; if (x>=MOD)x-=MOD; } inline void modSub(int &x,int y){ x-=y; if (x<0)x+=MOD; } void solve(int *a,int *res){ REP(i,n){ le[i]=i; while (le[i]>0 && a[le[i]-1]<=a[i])le[i]=le[le[i]-1]; } for (int i=n-1;i>=0;--i){ ri[i]=i; while (ri[i]<n-1 && a[ri[i]+1]<a[i])ri[i]=ri[ri[i]+1]; } REP(i,n)if (a[i]>=MOD)a[i]-=MOD; REP(i,n){ modAdd(res[1],a[i]); modSub(res[i-le[i]+2],a[i]); modSub(res[ri[i]-i+2],a[i]); modAdd(res[ri[i]-le[i]+3],a[i]); } REP(times,2)for (int i=2;i<=n;++i){ modAdd(res[i],res[i-1]); } } int main(){ scanf("%d",&n); REP(i,n)scanf("%d",a+i),a[i]+=i+1; REP(i,n)scanf("%d",b+i),b[i]+=i+1; solve(a,aa); solve(b,bb); for (int i=1;i<=n;++i)printf("%d ",int((LL)aa[i]*bb[i]%MOD)); printf("\n"); return 0; }