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;
}