2018 Multi-University Training Contest 1
1001:
推出公式只需要1/x+1/y+1/z=1的整数解,有2、4、4和3、3、3和2、3、6。但2、3、6得到答案比3、3、3小,故只判断前两种可能。
1 #include <cstdio> 2 #include <cstring> 3 #include <string> 4 #include <algorithm> 5 #include <iostream> 6 #include <map> 7 #include <stack> 8 #include <vector> 9 #include <queue> 10 #include <set> 11 using namespace std; 12 13 const int MAX=1e5+5; 14 long long t,n; 15 long long a,b; 16 17 int main(){ 18 scanf("%lld",&t); 19 while(t--){ 20 a=b=0; 21 scanf("%lld",&n); 22 if(n%4==0){ 23 a=n/2*n/4*n/4; 24 } 25 if(n%3==0) 26 b=n/3*n/3*n/3; 27 if(n%4&&n%3) 28 puts("-1"); 29 else 30 printf("%lld\n",max(a,b)); 31 } 32 33 return 0; 34 }
1002:
把每个串能够匹配的处理掉,得到剩余的左括号和右括号数,再按贡献大小排序,最后合并成一个串。
#include <cstdio> #include <cstdlib> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <vector> #include <string> #include <map> using namespace std; const int MAX=1e5+5; int t,n; char str[MAX]; struct node{ int l,r; }p[MAX]; int ans; int cmp(node a,node b){ int tmpa,tmpb; tmpa=min(a.l,b.r); tmpb=min(a.r,b.l); if(tmpa==tmpb) return a.l>b.l; return tmpa>tmpb; } int main(){ int i,j; //freopen("1002.in","r",stdin); //freopen("1003.out","w",stdout); scanf("%d",&t); while(t--){ ans=0; scanf("%d",&n); for(i=0;i<n;i++){ scanf("%s",&str); int len=strlen(str); p[i].l=p[i].r=0; for(j=0;j<len;j++){ if(str[j]=='(') p[i].l++; else{ if(p[i].l) p[i].l--,ans++; else p[i].r++; } } } sort(p,p+n,cmp); int l=0; for(i=0;i<n;i++){ if(p[i].r>l){ ans+=l; l=0; } else{ ans+=p[i].r; l-=p[i].r; } l+=p[i].l; } printf("%d\n",ans*2); } return 0; }
1003:
贪心排一下序就行,先按x坐标再按y坐标,每次选三个即可
#include <cstdio> #include <cstdlib> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <vector> #include <string> #include <map> using namespace std; struct point { long long x,y; int id; }; point po[4010]; int n; void init() { memset(po,0,sizeof(po)); } bool cmp(const point &a,const point &b) { if(a.y==b.y) return a.x<b.x; return a.y<b.y; } int main() { int i; int t; scanf("%d",&t); while(t--) { init(); scanf("%d",&n); for(i=1;i<=3*n;i++) { cout<<i<<endl; scanf("%lld%lld",&po[i].x,&po[i].y); po[i].id=i; } sort(po+1,po+1+3*n,cmp); int pos=1; for(i=1;i<=n;i++) { printf("%d %d %d\n",po[pos++].id,po[pos++].id,po[pos++].id); } } return 0; }
1004:
添加n条端点为[i,i]的长度为1的线段,将所有线段以左端点为第一关键字,线段长度为第二关键字排序,依次处理。设置L,R两个指针和一个小根堆(初始存了1~n的数字),每次处理一条线段时先将L到线段左端点的数字加入小根堆,再把R到线段右端的数字从小根堆中取数字更新。
1 #include<queue> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<algorithm> 6 7 #define maxn 200000+5 8 9 using namespace std; 10 11 priority_queue <int,vector<int>,greater<int> > q; 12 13 struct Data{ 14 int l,r,len; 15 bool operator <(const Data &T)const{ 16 if(l==T.l) return len>T.len; 17 else return l<T.l; 18 } 19 }t[maxn]; 20 21 int res[maxn]; 22 int n,m; 23 24 int main(){ 25 int T; 26 scanf("%d",&T); 27 while(T--){ 28 memset(res,0,sizeof(res)); 29 scanf("%d%d",&n,&m); 30 while(!q.empty()) q.pop(); 31 for(int i=1;i<=n;i++) q.push(i); 32 for(int i=1;i<=m;i++){ 33 scanf("%d%d",&t[i].l,&t[i].r); 34 t[i].len=t[i].r-t[i].l+1; 35 } 36 for(int i=1;i<=n;i++) t[++m].l=i,t[m].r=i,t[m].len=1; 37 sort(t+1,t+1+m); 38 int L=1,R=0; 39 for(int i=1;i<=m;i++){ 40 while(L<t[i].l) q.push(res[L]),L++; 41 while(R<t[i].r) res[++R]=q.top(),q.pop(); 42 } 43 printf("%d",res[1]); 44 for(int i=2;i<=n;i++) printf(" %d",res[i]); 45 puts(""); 46 } 47 return 0; 48 }
1005:
1007:
找规律,打表
首先把a[]序列打表出来:
将相同元素放到同一行发现这样的一个三角形
1
1
2 2
3
4 4 4
5
6 6
7
8 8 8 8
发现这个a[]中每个元素出现的次数刚好是因子中所含2的数量+1
然后就好做了,找一找这个三角形规律,注意打表,log*log的复杂度过不了
#include <cstdio> #include <cstdlib> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <vector> #include <string> #include <map> using namespace std; const long long mod=1e9+7; const long long inv=500000004; long long num_2[100],mi[100],biao[100],biao_cnt[100]; long long n,num,sum; long long ans; void init() { num=0; ans=0; sum=0; } long long fun(long long now,int i) { long long pos=now; long long flag=(pos%mod)*((pos+1)%mod)%mod; flag=(flag*inv)%mod; long long tmp=flag; long long cnt=pos; long long t=flag; pos/=2; while(pos>0) { tmp=(tmp+((t+now/2)%mod)*inv)%mod; cnt+=pos; pos/=2; t=(((t+now/2)%mod)*inv)%mod; } tmp=(tmp+(sum%mod*cnt%mod)%mod)%mod; biao_cnt[i]=cnt; sum+=now; return (tmp%mod+mod)%mod; } int main() { //freopen("123.in","r",stdin); //freopen("123.out","w",stdout); int i; num_2[0]=0; mi[0]=1; biao[0]=fun(mi[0],0); long long flag=1; for(i=1;i<=62;i++) { flag*=2; mi[i]=flag; num_2[i]=flag-1; sum=0; biao[i]=fun(mi[i],i); // cout<<biao_cnt[i]<<endl; } int t; scanf("%d",&t); while(t--) { init(); scanf("%lld",&n); long long tmp=n-1; for(i=62;i>0;i--) { if(tmp==0) break; if(num_2[i]>tmp) continue; num+=(num_2[i]+1)/2; tmp-=num_2[i]; } long long cnt=num; long long pos=0; int xx=62; sum=0; while(cnt>0) { for(i=xx;i>=0;i--) { if(mi[i]<=cnt) { pos=mi[i]; break; } } long long flag=biao[i]; flag=(flag+(sum%mod)*(biao_cnt[i]%mod))%mod; ans=(ans+flag)%mod; cnt-=pos; sum+=pos; } ans=(ans+((num+1)%mod)*(tmp%mod)+1)%mod; printf("%lld\n",ans); } return 0; }
1008:
MQ-Similar实际上就是 A 和 B 的笛卡尔树一样,这样我们就有了一个二叉树,然后可以在树上分析了。
考虑到B中有元素相同的概率是 0 ,于是可以假设 BB 里面元素互不相同,也就是说可以假定是一个排列。
显然,符合笛卡尔树的排列就是这个树的拓扑序列个数,就是n!/2∏sizei。然后显然每个排列期望的和是n/2,于是答案就是n/2∏sizei
由于我们只需要知道笛卡尔树的大小,所以可以不通过显性建树,用单调栈维护一下即可
#include <cstdio> #include <cstdlib> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <vector> #include <string> #include <map> using namespace std; const long long mod=1e9+7; int ai[3000010]; int n; int st[3000010],head,sum_left[3000010],sum[3000010]; long long inv[1000010]; void init() { head=0; } struct FastIO { static const int S = 200; int wpos; char wbuf[S]; FastIO() :wpos(0) {} inline int xchar() { static char buf[S]; static int len = 0, pos = 0; if (pos == len) pos = 0, len = fread(buf, 1, S, stdin); if (pos == len) exit(0); return buf[pos++]; } inline int read() { int s = 1, c = xchar(), x = 0; while (c <= 32) c = xchar(); if (c == '-') s = -1, c = xchar(); for (; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0'; return x * s; } ~FastIO() { if (wpos) fwrite(wbuf, 1, wpos, stdout), wpos = 0; } }io; int main() { //freopen("1008.in","r",stdin); //freopen("text.out","w",stdout); int i,j; int t; inv[1]=1; for(i=2;i<=1000000;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod; t=io.read(); while(t--) { n=io.read(); init(); for(i=1;i<=n;i++) { ai[i]=io.read(); } for(i=1;i<=n;i++) { sum[i]=0; sum_left[i]=0; while(head!=0&&ai[st[head]]<ai[i]) { sum[st[head]]=i-sum_left[st[head]]; head--; } if(head==0) sum_left[i]=1; else sum_left[i]=st[head]+1; st[++head]=i; } for(i=2;i<=head;i++) sum[st[i]]=n-sum_left[st[i]]+1; sum[st[1]]=n; long long ans=1; for(i=1;i<=n;i++) { ans=(ans*inv[sum[i]])%mod; } ans=(ans*n)%mod*inv[2]%mod; printf("%lld\n",ans); } return 0; }
1011:
随便算算
#include <cstdio> #include <cstring> #include <string> #include <algorithm> #include <iostream> #include <map> #include <stack> #include <vector> #include <queue> #include <set> using namespace std; const int MAX=1e5+5; int a,b,x,y,t,flag,p; char str[MAX]; int main(){ int i; scanf("%d",&t); while(t--){ x=y=flag=0; scanf("%d%d",&a,&b); scanf("%s",&str); for(i=0;i<strlen(str);i++){ if(str[i]=='.') flag=1; if(str[i]=='+') p=1; if(str[i]=='-') p=-1; if(flag&&str[i]>='0'&&str[i]<='9') y=str[i]-'0'; if(!flag&&str[i]>='0'&&str[i]<='9'){ x=str[i]-'0'; if(str[i+1]>='0'&&str[i+1]<='9'){ x*=10; x+=str[i+1]-'0'; i++; } } } if(p==1){ if(x<8){ int h=8-x; a-=h; if(a<0) a+=24; } else{ int h=x-8; a+=h; if(a>=24) a-=24; } int m=6*y; b+=m; if(b>=60){ a++; if(a>=24) a-=24; b-=60; } } else{ int h=x+8; a-=h; if(a<0) a+=24; int m=6*y; b-=m; if(b<0){ a--; if(a<0) a+=24; b+=60; } } printf("%0.2d:%0.2d\n",a,b); } return 0; }