弱鸡儿终于没爆零Day7
谢谢lpf 终于没爆零了
删除(del)
【题目描述】
现在,我的⼿上有 n 个数字,分别是 a1,a2,a3,...,an。 我现在需要删除其中的 k 个数字。当然我不希望随随便便删除,我希望删除 k 数字之后,剩下的 n−k 个数中有最多的不同的数。
【输入格式】
第一行两个正整数 n 和 k,含义如题目描述。 接下来一行,有 n 个非负整数,分别是 a1 到 an。
【输出格式】
一共一个整数 ans,表示删除了 k 个数字后最多的不同的数的个数。
【样例输入】
4 1
1 3 1 2
【样例输出】
3
数据范围
对于 30% 的数据,n≤10,ai ≤10。
对于 60% 的数据,n≤100,ai ≤100。
对于 80% 的数据,n≤10^5,ai ≤10^5。
对于 100% 的数据,n≤10^5,ai ≤10^9。
思路 排序+去重
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 const int mod=999979; 7 const int N=1e5+10; 8 int tot,head[mod+5],nxt[N],edge[N],num[N],n,k; 9 void add(int num){ 10 int x=num&mod; 11 for(int i=head[x];i;i=nxt[i]){ 12 if(edge[i]==num) 13 return ;//出现过 14 } 15 //没出现过 16 edge[++tot]=num; 17 nxt[tot]=head[x]; 18 head[x]=tot; 19 } 20 //tot即为不重复的元素个数 21 inline int read(){ 22 int res=0; 23 char ch=getchar(); 24 while(ch<'0' || ch>'9'){ 25 ch=getchar(); 26 } 27 while(ch>='0'&&ch<='9'){ 28 res=res*10+ch-'0'; 29 ch=getchar(); 30 } 31 return res; 32 } 33 int main(){ 34 freopen("del.in","r",stdin); 35 freopen("del.out","w",stdout); 36 n=read(); 37 k=read(); 38 if(n==0 || n==k){ 39 cout<<"0"; 40 return 0; 41 } 42 for(int i=1;i<=n;i++){ 43 int num; 44 num=read(); 45 add(num); 46 } 47 printf("%d\n",min(tot,max(0,n-k))); 48 return 0; 49 }
这里我用哈希表qaq 其实不用那么麻烦的 离散化更好写码量也不大
T2蚂蚁移动
(mravi.pas/c/cpp)
【问题描述】
有一根尺子,长度L<=200000,在上面有N(N<=70000,N<L)只蚂蚁,且没有两只蚂蚁初始位置相同。每只蚂蚁有一个初始方向(左或者右),且它们会爬行,速度都是每秒一个长度单位。当它们碰到另外一个蚂蚁或者尺子的边缘时,它们会立即改变移动的方向(即反向)。
给定尺子的长度,蚂蚁的只数,以及所有蚂蚁初始的位置和方向。要你求第T秒时每只蚂蚁的位置(1<=T<=1000000)。
【输入格式】
第一行两个整数L和T。
第二行一个整数N,表示蚂蚁的只数。
接下来的每行由两部分组成。第一部分是一个整数,表示该蚂蚁的初始位置。第二部分是一个字母,表示初始方向:D表示向右,L表示向左。两部分中间空格。
【输出格式】
N个整数,表示每只蚂蚁的最终位置。无需按照蚂蚁的原先编号输出,只要按照最终位置坐标递增(非降)的顺序输出坐标即可。
【输入输出样例1】
mravi.in |
mravi.out |
3 5 1 1 D |
0 |
【输入输出样例2】
mravi.in |
mravi.out |
5 5 2 2 D 4 L |
1 3 |
【输入输出样例3】
mravi.in |
mravi.out |
8 10 5 1 L 3 L 4 D 6 L 7 D |
1 2 4 7 7 |
做这题前建议先看看洛谷P1007 独木桥https://www.luogu.org/problem/P1007
分情况讨论即可
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdio> 5 using namespace std; 6 int l,t,n; 7 int pos[70010],tot=0; 8 inline int read(){ 9 int res=0; 10 char ch=getchar(); 11 while(ch<'0' || ch>'9'){ 12 ch=getchar(); 13 } 14 while(ch>='0'&&ch<='9'){ 15 res=res*10+ch-'0'; 16 ch=getchar(); 17 } 18 return res; 19 } 20 21 int main() 22 { 23 freopen("mravi.in","r",stdin); 24 freopen("mravi.out","w",stdout); 25 l=read(); 26 t=read();//第t秒 27 n=read(); 28 t=t%(2*l); 29 for(int i=1;i<=n;i++){ 30 int x;//初始位置 31 x=read(); 32 char ch=getchar(); 33 if(ch=='D'){//向右走 34 int rem=l-x; 35 if(t<=rem)pos[++tot]=x+t; 36 else if(t>rem && t<=rem+l)pos[++tot]=l-(t-rem); 37 else if(t>rem+l)pos[++tot]=t-l-rem; 38 } 39 else{ 40 if(t<=x)pos[++tot]=x-t; 41 else if(t>x && t<=x+l)pos[++tot]=t-x; 42 else pos[++tot]=l-(t-x-l); 43 } 44 } 45 sort(pos+1,pos+n+1); 46 for(int i=1;i<=n;i++){ 47 printf("%d ",pos[i]); 48 } 49 return 0; 50 }
T3权值(weight)
【问题描述】
有一个长度为n的实数序列,,下标从1开始,其中第k个位置的实数为p · (sin(a · k + b) + cos(c · k + d) + 2),sin和cos采用弧度制,其中p,a,b,c,d均为给定的整数。你需要从这个序列中选择两个位置(可以相同),使前边的位置上的数字减去后边的位置上的数字最大。如果选择了两个相同的位置,那么差为0.
【输入】
一行六个整数p,a,b,c,d,n。
【输出】
一行一个实数表示最大的差值,保留六位小数。
【输入输出样例】
weight.in |
weight.out |
100 432 406 867 60 1000 |
399.303813 |
【数据范围】
对于30%的数据,1<=p,a,b,c,d<=1000,1<=n<=1000;
对于全部的数据,1<=p,a,b,c,d<=1000,1<=n<=10^6。
这题要用到cmath库里的sin(x) cos(x)函数 该函数里面装的不是角度而是数值(弧度制)
1 #include<iostream> 2 #include<cstring> 3 #include<cmath> 4 #include<cstdio> 5 using namespace std; 6 double p,a,b,c,d; 7 int n; 8 double s[1000100]; 9 double dpmin[1000100],dpmax[1000100]; 10 int main() 11 { 12 freopen("weight.in","r",stdin); 13 freopen("weight.out","w",stdout); 14 scanf("%lf%lf%lf%lf%lf%d",&p,&a,&b,&c,&d,&n); 15 for(int i=1;i<=n;i++){ 16 s[i]=(double)(sin(a*i+b)+cos(c*i+d)+2); 17 } 18 dpmin[n]=s[n]; 19 for(int i=n-1;i>=1;i--){ 20 dpmin[i]=min(s[i],dpmin[i+1]); 21 } 22 dpmax[1]=s[1]; 23 for(int i=2;i<=n;i++){ 24 dpmax[i]=max(s[i],dpmax[i-1]); 25 } 26 double ans=0; 27 for(int i=1;i<=n;i++){ 28 ans=max(ans,dpmax[i]-dpmin[i]); 29 } 30 printf("%.6lf",p*ans); 31 return 0; 32 }
运用了dp思想 开设两个数组分别表示从头到某结点的最大值和从尾到某结点的最小值
对于同一个节点 前面最大值减去后面最小值的即为答案所求最大值 枚举即可
T4
dvd的逆序对(sequence)
【问题描述】
给你n,k求1~n有多少排列有恰好k个逆序对。逆序对:对于i,j,满足i<j,且p[i]>p[j]的点对数
【样例输入】
一行两个整数n,k
【样例输出】
输出一个整数,表示答案对1000000007取模后的结果
【输入输出样例】
sequence.in |
sequence.out |
4 1 |
3 |
【数据范围】
对于10%的数据 n<=10
对于30%的数据 k<=50
对于100%的数据 1<=n,k<=1000 且 k<=n*(n-1)/2
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const long long mod=1000000007; long long f[1005][1005]; long long sum[1005]; long long tot; int main() { freopen("sequence.in","r",stdin); freopen("sequence.out","w",stdout); int N,K; cin>>N>>K; f[0][0]=1; for(int i=1;i<=N;i++){ sum[0]=f[i-1][0]; for(int j=1;j<=K;j++){ sum[j]=(sum[j-1]+f[i-1][j])%mod; } for(int j=0;j<=K;j++){ if(j-i>=0) f[i][j]=(f[i][j]+(sum[j]-sum[j-i])%mod+mod)%mod; else f[i][j]=sum[j]%mod; } } printf("%lld",f[N][K]%mod); return 0; }