(D1T1) 玩具谜题((OK))
(D1T3) 换教室((OK))
(D2T1) 组合数问题((OK))
(D2T2) 蚯蚓((OK))
(D2T3) 愤怒的小鸟((OK))
(2016)年的只有一道毒瘤题没做(!!!)
(D1T1)简单模拟就好,字符串(名字/职业)与数字编号的映射直接用(map)就好.然后朝内向左=朝外向右,朝内向右=朝外向左.
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
map<int,string>rev;
const int N=1e5+5;
int cx[N];
int main(){
int n,m;cin>>n>>m;
for(int i=1;i<=n;++i){
int x;cin>>x;string s;cin>>s;
rev[i]=s;cx[i]=x;
}
int now=1;
while(m--){
int x,y;cin>>x>>y;
if(!x){
if(!cx[now]){
now-=y;if(now<=0)now+=n;
}
else{
now+=y;if(now>n)now-=n;
}
}
else{
if(!cx[now]){
now+=y;if(now>n)now-=n;
}
else{
now-=y;if(now<=0)now+=n;
}
}
}
cout<<rev[now]<<endl;
return 0;
}
(D1T2)咕咕咕
(D1T3)不久前谢总讲概率期望的时候写过.博客
(D2T1)因为每一次的(k)都是不变的,然后看一下数据范围猜测一下是(n^2)预处理.然后组合数是可以递推的,因为(sum_{i=0}^nsum_{j=0}^i)是一个三角矩阵,所以我们递推出(f[i][j])表示(C_i^j)之后(处理的时候就取模),可以用二维前缀和来维护(f[i][j]=0)的数量(就如果取模之后等于零,就把矩阵中的这个位置赋值为(1),其它都是(0),然后就可以二维前缀和处理了).感觉讲的不是很清楚,代码还是很好懂的.
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=2005;
int f[N][N],g[N][N],sum[N][N];
int main(){
int T=read(),k=read();
f[0][0]=1;
for(int i=1;i<=2000;++i){
f[i][0]=1;
for(int j=1;j<=i;++j){
f[i][j]=(f[i-1][j-1]+f[i-1][j])%k;
if(!f[i][j])g[i][j]=1;
}
}
for(int i=1;i<=2000;++i)
for(int j=1;j<=2000;++j)
sum[i][j]=g[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
while(T--){
int n=read(),m=read();
printf("%d
",sum[n][m]);
}
return 0;
}
(D2T2)写了整整一个晚上.
讲个笑话:
刚开始好不容易才写出个(mlog_m)的算法,以为就是正解,结果交上去(T)了(3)个点,心想:肯定是(pq)的常数大了,先不开(O_2),先自己卡一下常.
然后就去卡了半个小时的常,发现还是(T)了(3)个点.
最后自信满满地开了一波(O_2),心想肯定能过,结果还是(T)了(3)个点.
然后再去仔细看一下数据范围,才发现(mlog_m)根本过不了.正解必须是(O(n))的.
(lyh):(85)分都是送分的啊,直接开一个堆或者(multiset)来模拟整个过程就好了.
(我写个堆的做法,还写了一个多小时,太菜了~~~)
讲正解.发现题目隐藏的单调性,就是我们每次选当前最大的拎出来,拆成两个部分,一个部分大,一个部分小,然后两个部分分开来看,在每个部分中,先拆出的一定总是比后拆出的大.
所以我们可以把堆换成三个数组(一个是初始的蚯蚓数组,一个是拆成的较小的那一部分,一个是拆成的较大的那一部分),三个数组中的元素一定都是单调递减的,然后每次要选最大的元素的时候就比较三个数组的队头即可.
先把(mlog_m)的做法放出来.
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
priority_queue<ll>Q;
int main(){
int n=read(),m=read(),q=read(),u=read(),v=read(),t=read();
for(int i=1,st;i<=n;++i)st=read(),Q.push(st);
for(int i=1;i<=m;++i){
ll x=Q.top();Q.pop();x+=1ll*(i-1)*q;
if(!(i%t))printf("%lld ",x);
ll y=(ll)x*u/v;
Q.push(y-q*i);Q.push(x-y-q*i);
}printf("
");
for(int i=1;i<=n+m;++i){
if(!(i%t))printf("%lld ",Q.top()+1ll*m*q);
Q.pop();
}printf("
");
return 0;
}
正解做法(获取性质之后就是一顿模拟了)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=1e5+5;
const int M=7e6+5;
int n,m,q,u,v,t;
int a[N],q1[M],q2[M];
inline int check1(int tim,int i,int j,int k){
int x=a[i]+(tim-1)*q,y=q1[j]+(tim-1-j)*q,z=q2[k]+(tim-1-k)*q;
if(x>=y&&x>=z)return 1;
if(y>=x&&y>=z)return 2;
return 3;
}
inline int check2(int tim,int j,int k){
int y=q1[j]+(tim-1-j)*q,z=q2[k]+(tim-1-k)*q;
if(y>=z)return 2;
return 3;
}
int main(){
n=read(),m=read(),q=read(),u=read(),v=read(),t=read();
for(int i=1;i<=n;++i)a[i]=read();sort(a+1,a+n+1,greater<int>());
int a1=1,l1=1,l2=1,r1=0;
for(int i=1;i<=m;++i){
int en;
if(a1<=n)en=check1(i,a1,l1,l2);//注意初始数组的数可能都用完了
else en=check2(i,l1,l2);
if(en==1){
int x=a[a1]+(i-1)*q;
if(!(i%t))printf("%d ",x);
int y=(ll)x*u/v;x-=y;//x*u会爆int
q1[i]=min(x,y);q2[i]=max(x,y);++a1;
continue;
}
if(en==2){
int x=q1[l1]+(i-1-l1)*q;
if(!(i%t))printf("%d ",x);
int y=(ll)x*u/v;x-=y;
q1[i]=min(x,y);q2[i]=max(x,y);++l1;
continue;
}
if(en==3){
int x=q2[l2]+(i-1-l2)*q;
if(!(i%t))printf("%d ",x);
int y=(ll)x*u/v;x-=y;
q1[i]=min(x,y);q2[i]=max(x,y);++l2;
continue;
}
}printf("
");
for(int i=1;i<=n+m;++i){
int en;
if(a1<=n)en=check1(i,a1,l1,l2);
else en=check2(i,l1,l2);
if(en==1){
if(!(i%t))printf("%d ",a[a1]+m*q);
++a1;
}
if(en==2){
if(!(i%t))printf("%d ",q1[l1]+(m-l1)*q);
++l1;
}
if(en==3){
if(!(i%t))printf("%d ",q2[l2]+(m-l2)*q);
++l2;
}
}printf("
");
return 0;
}
(D2T3)不久前考过,今天借此发现了以前博客的一个锅.