codeforce Hello 2020 A~E
题目链接:http://codeforces.com/contest/1284
给数字,求s字符串数组中对应命名+t字符串数组中对应命名,取余即可
#include<bits/stdc++.h> using namespace std; int main() { int n,m; string s[30],t[30]; cin>>n>>m; for(int i=0;i<n;i++)cin>>s[i]; for(int i=0;i<m;i++)cin>>t[i]; int q; cin>>q; while(q--) { int y; cin>>y; cout<<s[(y-1)%n]<<t[(y-1)%m]<<endl; } return 0; }
B.New Year and Ascent Sequence
给n组数,每组数先说明有多少个数,再依次给出,n组数可以左右相接,构成组成n*n组数
如果数组a[]里存在i<j且a[i]<a[j],则符合要求,计算这n*n组里共有多少组数符合要求。
思路:一组数可以和自己拼接,也可以拼在别人前面/后面。
如果它本身就含有升序,则无论怎么拼都符合要求,这一类数放一堆,每组对答案的贡献应为n*2-1,因为自己与自己相组不分前后。
但是这样重复计算了贡献,故应改成(n-cnt)*2-1,cnt为截止到第i个时,本身含有升序的组数。
重复计算贡献样例
input: 3 2 0 2 2 0 2 2 0 2 output: 9
如果本身不含有升序(即全递减),记录数组里最大值H[i]、最小值L[i],这另一类数放一堆。
在这堆里,每组数对答案的贡献为,该堆中H[i]大于L[该组i]的数量。
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+10; int s[1000050]; int flag[maxn],h[maxn],l[maxn]; vector<int> high,low; int main() { long long ans=0; int n,cnt=0; cin>>n; for(int i=0;i<n;i++) { int len; cin>>len; int tmph=0,tmpl=1e6; for(int j=0;j<len;j++) { scanf("%d",&s[j]); if(j!=0&&s[j]>s[j-1])flag[i]=1; tmph=max(tmph,s[j]); tmpl=min(tmpl,s[j]); } if(!flag[i]) { h[i]=tmph; l[i]=tmpl; high.push_back(tmph); low.push_back(tmpl); } } sort(high.begin(),high.end()); sort(low.begin(),low.end()); int size=high.size(); for(int i=0;i<n;i++) { if(flag[i]==1)ans+=((n-cnt)*2-1),cnt++; else { int num=upper_bound(high.begin(),high.end(),l[i])-high.begin(); ans+=size-num; } } cout<<ans<<endl; return 0; }
(先放个人思路,下有正解)
n的全排列(n!种情况)里找,每种情况里找符合以下条件的所有i,j的组数,答案为所有情况组数之和
从a[i]到a[j]里,最大值max-最小值min=j-i
暴力枚举答案:1,6,32,180,1116,7728,59904,518400
枚举从3推到4的情况才发现规律,按理应该加上n=3时的r的,不过发现系数有规律就直接*(n+1)/2了
#include<bits/stdc++.h> using namespace std; int jie[250050]; int extgcd(int a,int b,int& x,int& y) { int d=a; if(b!=0) { d=extgcd(b,a%b,y,x); y-=(a/b)*x; } else { x=1; y=0; } return d; } int mod_inverse(int a,int m) { int x,y; extgcd(a,m,x,y); return(m+x%m)%m; } int main() { int n,m; long long r=0; cin>>n>>m; jie[1]=1; for(int i=2;i<=n;i++) { jie[i]=1ll*jie[i-1]*i%m; } for(int i=1;i<=n;i++) { r=(r+1ll*jie[i]*jie[n-i+1]%m)%m; } //*1,*1.5,*2,*2.5,*3,*3.5...... //2*1=1,4*1.5=6,16*2=32,72*2.5=180 r=r*(n+1)%m; r=r*mod_inverse(2,m)%m;//除以2等于乘上逆元 cout<<r<<endl; return 0; }
标程很简单啊emm......考虑[l, r]组合的贡献,l - r 在每个项里都有出现,当作整体来看
#include <bits/stdc++.h> using namespace std; const int MAXN = 250005; using lint = long long; using pi = pair<int, int>; int n, mod; lint fact[MAXN]; int main(){ fact[0] = 1; cin >> n >> mod; for(int i=1; i<=n; i++) fact[i] = fact[i-1] * i % mod; lint ret = 0; for(int i=1; i<=n; i++){ ret += (n - i + 1) * (fact[i] * fact[n - i + 1] % mod); ret %= mod; } cout << ret << endl; }
题意&思路:https://blog.csdn.net/sigh_/article/details/103838790
个人代码:
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+10; const int inf=1e9+10; struct Node { int sa,ea,sb,eb; Node(){} Node(int sa_,int ea_,int sb_,int eb_):sa(sa_),ea(ea_),sb(sb_),eb(eb_){} bool operator<(const Node &rhs) { if(sa==rhs.sa)return ea<rhs.ea; return sa<rhs.sa; } }P[maxn];//要用这句话,又定义了构造函数,就得加Node(){} int smax[maxn<<2],smin[maxn<<2]; void up(int p) { smax[p]=max(smax[p<<1],smax[p<<1|1]); smin[p]=min(smin[p<<1],smin[p<<1|1]); } void build(int p,int l,int r) { if(l==r) { smax[p]=P[l].sb; smin[p]=P[l].eb; return; } int mid=l+r>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r); up(p); } int querymin(int p,int l,int r,int x,int y) { if(x<=l&&r<=y)return smin[p]; int mid=l+r>>1; int res=inf; if(x<=mid)res=min(res,querymin(p<<1,l,mid,x,y)); if(y>mid)res=min(res,querymin(p<<1|1,mid+1,r,x,y)); return res; } int querymax(int p,int l,int r,int x,int y) { if(x<=l&&r<=y)return smax[p]; int mid=l+r>>1; int res=-inf; if(x<=mid)res=max(res,querymax(p<<1,l,mid,x,y)); if(y>mid)res=max(res,querymax(p<<1|1,mid+1,r,x,y)); return res; } bool solve(int n) { sort(P+1,P+1+n); build(1,1,n); for(int i=1;i<=n;i++) { int pos=lower_bound(P+1,P+1+n,Node(P[i].ea,inf,0,0))-P-1; //pos∈[0,n],对应P[pos+1] if(!(i+1<=pos))continue;//a场地无冲突 //a场地与[i+1,pos]都冲突 //b场地也需要冲突,如果b场地[i+1,pos]里有一个不冲突即为false //最小的eb比P[i].sb小,或者最大的sb比P[i].eb大 if(querymin(1,1,n,i+1,pos)<P[i].sb||querymax(1,1,n,i+1,pos)>P[i].eb) return false; } return true; } int main() { int n,sig=1; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d%d%d",&P[i].sa,&P[i].ea,&P[i].sb,&P[i].eb); } sig&=solve(n); for(int i=1;i<=n;i++) { swap(P[i].sa,P[i].sb); swap(P[i].ea,P[i].eb); } sig&=solve(n); if(sig)printf("YES\n"); else printf("NO\n"); return 0; }
E.New Year and Castle Construction
给n个点,问存在多少个四个点围成的四边形(可能是凹四边形,这样围成的就是三角形)严格包围某个点。
不存在三点共线,支持复杂度O(n*n*logn)。
所有情况数减去不能围成四边形的组数,即为答案。
参考:https://blog.csdn.net/qq_43326267/article/details/103845048
把弧度制转成角度值放进vector会wa15,盲猜还是精度问题
#include<bits/stdc++.h> using namespace std; const int maxn=3005; long double x[maxn],y[maxn],pi=acos(-1.0L); //不开long double有精度问题 int main() { int n; cin>>n; for(int i=0;i<n;i++)cin>>x[i]>>y[i]; long long res=1ll*n*(n-1)*(n-2)*(n-3)*(n-4)/24;//n个点选四个共有res种情况 for(int i=0;i<n;i++)//完全围住点i { vector<long double> v; for(int j=0;j<n;j++) { if(i==j)continue; v.push_back(atan2(y[j]-y[i],x[j]-x[i]));//求y相对于x的角度 } sort(v.begin(),v.end()); int size=n-1,index=0; for(int j=0;j<size;j++)//枚举另一个点 { while(index<j+size) { long double ang=v[index%size]-v[j];//index点相对于j点的实际角度,非升序,所以需要环形扫一遍 if(ang<0)ang+=2*pi; if(ang<pi)index++; else break;//在点i、j构成的线下方则break } //index是从相对于x的角度-180开始枚举到+180,枚举两轮 //枚举到相对于j的角度大于等于180为止,共有index-j个点,不包括j,故再-1 long long cnt=index-j-1; //点i、j构成的线(以该线为x轴)上方共有cnt个点,cnt个点随便取三个,与i,j点组合的情况都要减去 res-=1ll*cnt*(cnt-1)*(cnt-2)/6; } } cout<<res<<endl; return 0; }