NP(np)
Time Limit:1000ms Memory Limit:64MB
题目描述
LYK喜欢研究一些比较困难的问题,比如np问题。
这次它又遇到一个棘手的np问题。问题是这个样子的:有两个数n和p,求n的阶乘对p取模后的结果。
LYK觉得所有np问题都是没有多项式复杂度的算法的,所以它打算求助即将要参加noip的你,帮帮LYK吧!
输入格式(np.in)
输入一行两个整数n,p。
输出格式(np.out)
输出一行一个整数表示答案。
输入样例
3 4
输出样例
2
数据范围
对于20%的数据:n,p<=5。
对于40%的数据:n,p<=1000。
对于60%的数据:n,p<=10000000。
对于80%的数据:n<=10^18,p<=10000000。
对于另外20%的数据:n<=10^18,p=1000000007。
其中大致有50%的数据满足n>=p。
我的代码:
#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;
#define LL long long
LL n,p;
void solve(){
LL ans=1;
for(register LL i=2;i<=n;++i) ans=(ans*i)%p;
printf("%I64d\n",ans);
}
int Main(){
freopen("np.in","r",stdin);
freopen("np.out","w",stdout);
scanf("%I64d%I64d",&n,&p);
if(n>=p) { printf("0\n"); return 0; }
else solve();
fclose(stdin);fclose(stdout);
return 0;
}
int Aptal_is_My_son=Main();
int main(int argc,char *argv[]){ ; }
//正解:分块打表 我没打90分
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define LL long long
LL n,p;
LL a[110]={1,682498929,491101308,76479948,723816384,67347853,27368307,
625544428,199888908,888050723,927880474,281863274,661224977,623534362,
970055531,261384175,195888993,66404266,547665832,109838563,933245637,
724691727,368925948,268838846,136026497,112390913,135498044,217544623,
419363534,500780548,668123525,128487469,30977140,522049725,309058615,
386027524,189239124,148528617,940567523,917084264,429277690,996164327,
358655417,568392357,780072518,462639908,275105629,909210595,99199382,
703397904,733333339,97830135,608823837,256141983,141827977,696628828,
637939935,811575797,848924691,131772368,724464507,272814771,326159309,
456152084,903466878,92255682,769795511,373745190,606241871,825871994,
957939114,435887178,852304035,663307737,375297772,217598709,624148346,
671734977,624500515,748510389,203191898,423951674,629786193,672850561,
814362881,823845496,116667533,256473217,627655552,245795606,586445753,
172114298,193781724,778983779,83868974,315103615,965785236,492741665,
377329025,847549272,698611116};
int main(){
freopen("np.in","r",stdin);
freopen("np.out","w",stdout);
scanf("%I64d%I64d",&n,&p);
if(n>=p) { printf("0\n"); return 0; }
if(p==1000000007){
LL now=n/10000000;
LL ans=a[now];
for(LL i=now*10000000+1;i<=n;++i) ans=ans*i%p;
printf("%I64d\n",ans%p);
return 0;
}
LL ans=1;
for(int i=1;i<=n;++i) ans=ans*i%p;
printf("%I64d\n",ans%p);
fclose(stdin);fclose(stdout);
return 0;
}
看程序写结果(program)
Time Limit:1000ms Memory Limit:64MB
题目描述
LYK最近在准备NOIP2017的初赛,它最不擅长的就是看程序写结果了,因此它拼命地在练习。
这次它拿到这样的一个程序:
Pascal:
readln(n);
for i:=1 to n do read(a[i]);
for i:=1 to n do for j:=1 to n do for k:=1 to n do for l:=1 to n do
if (a[i]=a[j]) and (a[i] < a[k]) and (a[k]=a[l]) then ans:=(ans+1) mod 1000000007;
writeln(ans);
C++:
pcanf(“%d”,&n);
for (i=1; i<=n; i++) scanf(“%d”,&a[i]);
for (i=1; i<=n; i++) for (j=1; j<=n; j++) for (k=1; k<=n; k++) for (l=1; l<=n; l++)
if (a[i]==a[j] && a[i] < a[k] && a[k]==a[l]) ans=(ans+1)%1000000007;
printf(“%d\n”,ans);
LYK知道了所有输入数据,它想知道这个程序运行下来会输出多少。
输入格式(program.in)
第一行一个数n,第二行n个数,表示ai。
输出格式(program.out)
一个数表示答案。
输入样例
4
1 1 3 3
输出样例
4
数据范围
对于20%的数据n<=50。
对于40%的数据n<=200。
对于60%的数据n<=2000。
对于100%的数据n<=100000,1<=ai<=1000000000。
其中均匀分布着50%的数据不同的ai个数<=10,对于另外50%的数据不同的ai个数>=n/10。
题目本意:求满足这种情况的状态数a[i]==a[j]
#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
using namespace std;
#define MAXN 100000
int a[MAXN],n,ans;
map<int,int> Mp;
#define Mod 1000000007
int Main(){
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
scanf("%d",&n);
register int k,i;
for (i=1; i<=n; i++) scanf("%d",&a[i]),++Mp[a[i]];
for (i=1; i<=n; i++) for (k=1; k<=n; k++)
if ( a[i]<a[k] ) ans=(ans + Mp[a[k]] * Mp[a[i]])%1000000007;
printf("%d\n",ans);
fclose(stdin);fclose(stdout);
return 0;
}
int Aptal_is_My_son=Main();
int main(int argc,char *argv[ ]){ ; }
选数字 (select)
Time Limit:3000ms Memory Limit:64MB
题目描述
LYK找到了一个n*m的矩阵,这个矩阵上都填有一些数字,对于第i行第j列的位置上的数为ai,j。
由于它AK了noip2016的初赛,最近显得非常无聊,便想到了一个方法自娱自乐一番。它想到的游戏是这样的:每次选择一行或者一列,它得到的快乐值将会是这一行或者一列的数字之和。之后它将该行或者该列上的数字都减去p(之后可能变成负数)。如此,重复k次,它得到的快乐值之和将会是它NOIP2016复赛比赛时的RP值。
LYK当然想让它的RP值尽可能高,于是它来求助于你。
输入格式(select.in)
第一行4个数n,m,k,p。
接下来n行m列,表示ai,j。
输出格式(select.out)
输出一行表示最大RP值。
输入样例
2 2 5 2
1 3
2 4
输出样例
11
数据范围
总共10组数据。
对于第1,2组数据n,m,k<=5。
对于第3组数据k=1。
对于第4组数据p=0。
对于第5,6组数据n=1,m,k<=1000。
对于第7,8组数据n=1,m<=1000,k<=1000000。
对于所有数据1<=n,m<=1000,k<=1000000,1<=ai,j<=1000,0<=p<=100。
样例解释
第一次选择第二列,第二次选择第二行,第三次选择第一行,第四次选择第二行,第五次选择第一行,快乐值为7+4+2+0+-2=11。
考场心血来潮,码了一个半小时的字,期望六七十分,实测40分。。
明显是贪心思路,然而贪心的思路是错的。。
GG
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define MAXN 1005
#define LL long long
#define INF 0x5fffffff
LL sum_hang[MAXN],sum_lie[MAXN];
int n,m,k,p;
LL ans=0,ans1,ans2;
inline void read(int &x){
x=0; int f=1; char c=getchar();
while(c>'9'||c<'0'){ if(c=='-') f=-1; c=getchar(); }
while(c>='0'&&c<='9'){ x=x*10+c-'0'; c=getchar(); } x*=f;
}
struct SegMent_Tree{ int l,r,maxx,lazy,pos; }tre_hang[MAXN<<2],tre_lie[MAXN<<2];
#define hang tre_hang
#define lie tre_lie
inline void UpDate_Hang(int u){
hang[u].maxx=max(hang[u<<1].maxx,hang[u<<1|1].maxx);
if(hang[u].maxx==hang[u<<1].maxx) hang[u].pos=hang[u<<1].pos;
else hang[u].pos=hang[u<<1|1].pos;
}
inline void UpDate_Lie(int u){
lie[u].maxx=max(lie[u<<1].maxx,lie[u<<1|1].maxx);
if(lie[u].maxx==lie[u<<1].maxx) lie[u].pos=lie[u<<1].pos;
else lie[u].pos=lie[u<<1|1].pos;
}
void Build_Tre_Hang(int u,int l,int r){
hang[u].l=l,hang[u].r=r,hang[u].maxx=-INF,hang[u].lazy=0;
if(l==r){ hang[u].maxx=sum_hang[l];hang[u].pos=l; return ; }
int Mid=l+r>>1;
Build_Tre_Hang(u<<1,l,Mid);
Build_Tre_Hang(u<<1|1,Mid+1,r);
UpDate_Hang(u);
}
void Build_Tre_Lie(int u,int l,int r){
lie[u].l=l,lie[u].r=r,lie[u].maxx=-INF,lie[u].lazy=0;
if(l==r){ lie[u].maxx=sum_lie[l];lie[u].pos=l; return ; }
int Mid=l+r>>1;
Build_Tre_Lie(u<<1,l,Mid);
Build_Tre_Lie(u<<1|1,Mid+1,r);
UpDate_Lie(u);
}
void Push_Down_Hang(int u){
hang[u<<1].lazy+=hang[u].lazy;
hang[u<<1|1].lazy+=hang[u].lazy;
hang[u<<1].maxx-=hang[u<<1].lazy,hang[u<<1|1].maxx-=hang[u<<1|1].lazy;
hang[u].lazy=0;
}
void Push_Down_Lie(int u){
lie[u<<1].lazy+=lie[u].lazy;
lie[u<<1|1].lazy+=lie[u].lazy;
lie[u<<1].maxx-=lie[u<<1].lazy,lie[u<<1|1].maxx-=lie[u<<1|1].lazy;
lie[u].lazy=0;
}
struct Ans{ int pos,maxx; };
Ans Query_Hang(int u,int l,int r){
if(l<=hang[u].l&&hang[u].r<=r){
Ans ret;
ret.pos = hang[u].pos;
ret.maxx = hang[u].maxx;
return ret;
}
int Mid=hang[u].l+hang[u].r>>1;
if(hang[u].lazy!=0) Push_Down_Hang(u);
if(l>Mid) return Query_Hang(u<<1|1,l,r);
else if(r<=Mid) return Query_Hang(u<<1,l,r);
else {
Ans retl=Query_Hang(u<<1,l,Mid);
Ans retr=Query_Hang(u<<1|1,Mid+1,r);
if(retl.maxx>retr.maxx) return retl;
else return retr;
}
}
Ans Query_Lie(int u,int l,int r){
if(l<=lie[u].l&&lie[u].r<=r){
Ans ret;
ret.pos = lie[u].pos;
ret.maxx = lie[u].maxx;
return ret;
}
int Mid=lie[u].l+lie[u].r>>1;
if(lie[u].lazy!=0) Push_Down_Lie(u);
if(l>Mid) return Query_Lie(u<<1|1,l,r);
else if(r<=Mid) return Query_Lie(u<<1,l,r);
else {
Ans retl=Query_Lie(u<<1,l,Mid);
Ans retr=Query_Lie(u<<1|1,Mid+1,r);
if(retl.maxx>retr.maxx) return retl;
else return retr;
}
}
void Change_Hang(int u,int pos){
if(hang[u].l==hang[u].r){ hang[u].maxx-=p*m; return ; }
int Mid=hang[u].l+hang[u].r>>1;
if(hang[u].lazy!=0) Push_Down_Hang(u);
if(pos<=Mid) Change_Hang(u<<1,pos);
else if(pos>Mid) Change_Hang(u<<1|1,pos);
UpDate_Hang(u);
}
void Change_Lie(int u,int pos){
if(lie[u].l==lie[u].r){ lie[u].maxx-=p*n; return ; }
int Mid=lie[u].l+lie[u].r>>1;
if(lie[u].lazy!=0) Push_Down_Lie(u);
if(pos<=Mid) Change_Lie(u<<1,pos);
else if(pos>Mid) Change_Lie(u<<1|1,pos);
UpDate_Lie(u);
}
void Modify_Hang(int u,int l,int r){
if(l<=hang[u].l&&hang[u].r<=r){
hang[u].maxx-=p;
hang[u].lazy+=p;
return ;
}
if(hang[u].lazy!=0) Push_Down_Hang(u);
int Mid=hang[u].l+hang[u].r>>1;
if(r<=Mid) Modify_Hang(u<<1,l,r);
else if(l>Mid) Modify_Hang(u<<1|1,l,r);
else {
Modify_Hang(u<<1,l,Mid);
Modify_Hang(u<<1|1,Mid+1,r);
}
UpDate_Hang(u);
}
void Modify_Lie(int u,int l,int r){
if(l<=lie[u].l&&lie[u].r<=r){
lie[u].maxx-=p;
lie[u].lazy+=p;
return ;
}
if(lie[u].lazy!=0) Push_Down_Lie(u);
int Mid=lie[u].l+lie[u].r>>1;
if(r<=Mid) Modify_Lie(u<<1,l,r);
else if(l>Mid) Modify_Lie(u<<1|1,l,r);
else {
Modify_Lie(u<<1,l,Mid);
Modify_Lie(u<<1|1,Mid+1,r);
}
UpDate_Lie(u);
}
void xolve(){
LL ans=-INF;
for(int i=1;i<=n;++i) ans=max(ans,sum_hang[i]);
for(int i=1;i<=m;++i) ans=max(ans,sum_lie[i]);
cout<<ans*k;
}
int main(){
freopen("select.in","r",stdin);
freopen("select.out","w",stdout);
read(n),read(m),read(k),read(p);
register int i,j; int x;
for (i=1; i<=n; ++i)
for (j=1; j<=m; ++j) read(x),sum_hang[i]+=x,sum_lie[j]+=x;
if(p==0){ xolve(); return 0; }
Build_Tre_Hang(1,1,n);
Build_Tre_Lie(1,1,m);
while(k--){
Ans Max_Hang=Query_Hang(1,1,n);
Ans Max_Lie=Query_Lie(1,1,m);
if(Max_Hang.maxx>Max_Lie.maxx){//抽 行
ans+=Max_Hang.maxx;
Change_Hang(1,Max_Hang.pos);
Modify_Lie(1,1,m);
}
else {//抽 列
ans+=Max_Lie.maxx;
Change_Lie(1,Max_Lie.pos);
Modify_Hang(1,1,n);
}
}
cout<<ans;
fclose(stdin);fclose(stdout);
return 0;
}
正解:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<queue>
using namespace std;
#define MAXN 1000005
#define MAXM 1005
#define LL long long
LL sum_hang[MAXM],sum_lie[MAXM],ans=-1e18,sum[MAXN],sum_[MAXN];
LL n,m,k,x,p;
priority_queue<LL,vector<LL> >q;
inline void read(LL &x){
x=0; int f=1; char c=getchar();
while(c>'9'||c<'0'){ if(c=='-') f=-1; c=getchar(); }
while(c>='0'&&c<='9'){ x=x*10+c-'0'; c=getchar(); } x*=f;
}
void xolve(){
register int i;register LL xx;
for( i=1; i<=m; ++i) q.push(sum_lie[i]);
for( i=1; i<=k; ++i) xx=q.top(),q.pop(),sum_[i]=sum_[i-1]+xx,q.push(xx-n*p);
while(!q.empty()) q.pop();
for( i=1; i<=n; ++i) q.push(sum_hang[i]);
for( i=1; i<=k; ++i) xx=q.top(),q.pop(),sum[i]=sum[i-1]+xx,q.push(xx-m*p);
for( i=0; i<=k; ++i)
ans=max(ans,sum[i]+sum_[k-i]-i*(k-i)*p);
cout<<ans;
}
int Main(){
freopen("select.in","r",stdin);
freopen("select.out","w",stdout);
read(n),read(m),read(k),read(p);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j) read(x),sum_hang[i]+=x,sum_lie[j]+=x;
xolve();
return 0;
}
int Aptal_is_My_Son=Main();
int main(int argc,char *argv[]){ ; }