2019西安多校联训 Day4
T1
大水题!!难度简单,显然的贪心策略即可,but...
思路:首先我们按与i点作战后活下来的士兵排序,然后
若当前剩余兵力足够直接减掉战斗死亡人数,如果不够就加
够再打它,但是!我们在考完试观察测试点时发现了这样一组
测试点:
2
7 4
5 1
emmm,这组测试点是什么意思呢??我们只需要4个人就可以
打下这座城市,但打这个城市的4个人中需要阵亡7人!(???喵喵喵???)
这就很尴尬了,当我们遇到这样的点时,我们只需凑够阵亡人数即可
不用管剩余人数(显然无人生还...)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 struct node{ 4 long long x,y; 5 }a[100010]; 6 long long n,mlast,ans; 7 long long T; 8 bool cmp(node p,node q){ 9 return (p.y-p.x)>(q.y-q.x); 10 } 11 inline void solve(){ 12 for(register int i=1;i<=n;i++){ 13 if(a[i].y<a[i].x&&mlast<a[i].x){ans+=(a[i].x-mlast),mlast=0;continue;} 14 else if(a[i].y<a[i].x&&mlast>=a[i].x){mlast-=a[i].x;continue;} 15 if(mlast>=a[i].y){ 16 mlast-=a[i].x; 17 continue; 18 } 19 else if(mlast<a[i].y){ 20 ans+=a[i].y-mlast; 21 mlast=a[i].y-a[i].x; 22 } 23 } 24 } 25 int main(){ 26 scanf("%lld",&T); 27 while(T--){ 28 memset(a,0,sizeof(a)); 29 ans=0;mlast=0; 30 scanf("%lld",&n); 31 for(register int i=1;i<=n;i++) scanf("%lld%lld",&a[i].x,&a[i].y); 32 sort(a+1,a+n+1,cmp); 33 solve(); 34 printf("%lld\n",ans); 35 } 36 return 0; 37 }
T2
这道题是一道数论题,对没有学过组合数同学非常不友好
(当然对我这种学过组合数但是只会杨辉三角的人也不友好....)
难度中等,因为有规律鸭
思路:首先我们需要知晓组合数的定义如下图
此乃组合数,那我们可以好好看题了,根据二项式定理我们知道
C0n+C1n+C2n+...Cnn=2^n;这是无比显然的,但平方过后规律产生了
变化,由作业帮可得(Cn0)^2+(Cn1)^2+(Cn2)^2+...+(Cnn)^2=(2n!)/(n!)^2
由这个式子再加上组合数的一些定理可得(反正我是不会证的)
ans=(2n)!*(n!)^(mod-2)%mod
其中(n!)^(mod-2)即为(n!)^2在mod下的逆元,所以除法变为乘法
然后在我们了解了公式之后打一个(2n)!的表,然后每次算完%一下mod
然后套个快速幂即可,数据过多可以再套个快读快写
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 long long n,T; 4 const long long modd=1e9+7; 5 long long dis[2000010],x[2000010]; 6 long long ans,ak,ac,wa; 7 long long ksm(long long a, long long b, long long p){ 8 long long ret=1; 9 while(b){ 10 if(b%2)ret=(ret*a)%p; 11 a=(a*a)%p; 12 b=b>>1; 13 } 14 return ret; 15 } 16 inline int read(){ 17 int X=0; bool flag=1; char ch=getchar(); 18 while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();} 19 while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();} 20 if(flag) return X; 21 return ~(X-1); 22 } 23 inline int write(long long X){ 24 if(X<0) {putchar('-'); X=~(X-1);} 25 int s[20],top=0; 26 while(X) {s[++top]=X%10; X/=10;} 27 if(!top) s[++top]=0; 28 while(top) putchar(s[top--]+'0'); 29 } 30 int main(){ 31 T=read(); 32 dis[0]=x[0]=1; 33 for(register int i=1;i<=2000000;i++) dis[i]=dis[i-1]*i%modd; 34 while(T--) 35 { 36 n=read(); 37 wa=ksm(dis[n],modd-2,modd); 38 ans=dis[2*n]*wa%modd*wa%modd; 39 write(ans); 40 putchar('\n'); 41 } 42 return 0; 43 }
T3
考试时我竟然想用线段树做!!(快停止这危险的想法),难度中上
其实本题正解是带有dp色彩的模拟...
思路:首先咱们可以发现一个回文字符串的性质,假设咱们有一字符串长度>=3
假设它左右端点的字符相同,那显然内侧也是一个回文串,其次我们很显然的发现只
有一个字符的串是回文串,然后长度为2的字符串只需要特判一下就可以确定是否为
回文串了,验证回文串算法get√
其次我们为什么称这道题为带有dp色彩的模拟呢?显然我们可以先O(n)处理一遍长度为1和长度为2的字符串,然后我即可找到dp式 dp[i][j]=dp[i][j-1]+dp[i+1][j]-dp[i+1][j-1];
非常优秀!而dp结束后我们只需要再判断整合后的字符串是否满足回文串即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 long long T,n; 4 int l,r; 5 int a[5010][5010]; 6 bool vis[5010][5010]; 7 char s[100010]; 8 bool check(int L,int R){ 9 if(vis[L][R]) return true; 10 else if(s[L]==s[R]) return check(L+1,R-1); 11 return false; 12 } 13 int main(){ 14 cin>>s+1; 15 int len=strlen(s+1); 16 scanf("%lld",&T); 17 for(register int i=1;i<=len;i++){ 18 vis[i][i]=true; 19 a[i][i]++; 20 a[i][i+1]=2; 21 if(s[i]==s[i+1]) a[i][i+1]++,vis[i][i+1]=true; 22 } 23 for(register int i=3;i<=len;i++){ 24 for(register int l=1;l+i-1<=len;l++){ 25 int r=l+i-1; 26 a[l][r]=a[l][r-1]+a[l+1][r]-a[l+1][r-1]; 27 if(check(l,r)) a[l][r]++,vis[l][r]=true; 28 } 29 } 30 while(T--){ 31 int num1,num2; 32 scanf("%d%d",&l,&r); 33 printf("%d\n",a[l][r]); 34 } 35 return 0; 36 }
end;