Solved | Pro.ID | Title | Author | Source | (AC/Submit)Ratio |
5380 | Travel with candy | SXYZ | 2015 Multi-University Training Contest 8 | (46/103)44.66% | |
5381 | The sum of gcd | SXYZ | 2015 Multi-University Training Contest 8 | (208/496)41.94% | |
5382 | GCD?LCM! | SXYZ | 2015 Multi-University Training Contest 8 | (73/139)52.52% | |
5383 | Yu-Gi-Oh! | SXYZ | 2015 Multi-University Training Contest 8 | (95/366)25.96% | |
5384 | Danganronpa | SXYZ | 2015 Multi-University Training Contest 8 | (278/506)54.94% | |
5385 | The path | SXYZ | 2015 Multi-University Training Contest 8 | (202/546)37.00% | |
5386 | Cover | SXYZ | 2015 Multi-University Training Contest 8 | (377/1092)34.52% | |
5387 | Clock | SXYZ | 2015 Multi-University Training Contest 8 | (325/469)69.30% | |
5388 | Geometer's Sketchpad | SXYZ | 2015 Multi-University Training Contest 8 | (21/58)36.21% | |
5389 | Zero Escape | SXYZ | 2015 Multi-University Training Contest 8 | (485/953)50.89% | |
5390 | tree | SXYZ | 2015 Multi-University Training Contest 8 | (28/160)17.50% |
HDU 5381php
給定一個數組,屢次詢問,求區間[l,r]內全部子區間的最大公約數之和。node
以a[x]爲右端點的gcd區間狀況最多隻有log(a[x])種,由於a[x]的因子只有sqrt(a[x])種,a[x]的因子的因子只有sqrt(sqrt(a[x]))種,....依次類推共有log(a[x])種ios
以下圖x=7的狀況數組
用sum[x]表示以x爲右端點的全部gcd區間和ide
sum[x]=gcd[1]*(r1-l1+1)+gcd[2]*(r2-l2+1)+...+gcd[k]*(rk-lk+1) (k<=log(a[x]))ui
遍歷數組,用樹狀數組維護sum,區間更新,動態查詢。spa
用f[l,r]表示區間[l,r]的全部子區間的gcd和,用d[i]表示區間[1,i]同時增長或者減小的量code
f[l,r]=d[l]*1+d[l+1]*2+...+d[r]*(r-l+1)blog
=sigma(d[i]*(i-l+1)) 排序
=sigma(d[i]*i) - (l-1)sigma(d[i]) (l<=i<=r)
用兩個數組分別維護d[i] 和 d[i]*i 便可。
計算gcd區間的位置時用了一個nxt數組,表示以x爲右端點時區間[nxt[j],j]的gcd值相同
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define low(x) (x&(-x)) #define maxn 10010 #define LL long long int n,m; int a[maxn]; LL ans[maxn]; int nxt[maxn]; int val[maxn]; struct node { int l,r,id; bool operator < (const node &b)const { return r<b.r; } }b[maxn]; LL bit[maxn*2][2]; void add(int t,int x,LL val) { while(x>0) { bit[x][t]+=val; x-=low(x); } } LL getsum(int t,int x) { LL ans=0; while(x<maxn) { ans+=bit[x][t]; x+=low(x); } return ans; } void update(int l,int r,int val) { add(0,r,(LL)val); add(0,l-1,-(LL)val); add(1,r,(LL)val*r); add(1,l-1,-(LL)val*(l-1)); } int gcd(int a,int b) { if(a%b==0)return b; else return gcd(b,a%b); } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); scanf("%d",&m); for(int i=1;i<=m;i++) { scanf("%d%d",&b[i].l,&b[i].r); b[i].id=i; } sort(b+1,b+m+1); memset(bit,0,sizeof(bit)); int k=1; nxt[1]=1; val[1]=a[1]; update(1,1,a[1]); for(int i=2;i<=n;i++) { val[i]=a[i]; nxt[i]=i; int j=i; while(j>0){ val[j]=gcd(val[j],a[i]); while(nxt[j]>1&&gcd(val[nxt[j]-1],val[j])==val[j]) { nxt[j]=nxt[nxt[j]-1]; } update(nxt[j],j,val[j]); // printf("i=%d %d %d %d\n",i,nxt[j],j,val[j]); j=nxt[j]-1; } while(k<=m&&b[k].r==i) { ans[b[k].id]=getsum(1,b[k].l)-(b[k].l-1)*getsum(0,b[k].l); k++; } } // printf("k=%d\n",k); for(int i=1;i<=m;i++) { // printf("l=%d r=%d ans=%d\n",b[i].l,b[i].r,ans[b[i].id]); printf("%lld\n",ans[i]); } } return 0; } /* 111 7 1 6 2 3 6 30 12 0 2 5 1 2 3 4 5 15 1 1 1 2 1 3 1 4 1 5 2 2 2 3 2 4 2 5 3 3 3 4 3 5 4 4 4 5 5 5 */
HDU5383
有n我的,每一個人有一個數字s[i], 有兩扇門的數字a, b 。數字均可以重複。現要求將這n我的分配到這兩個房間,或者只分配到一個房間,問方法數
x的數字根=(x-1)%9+1
dp[i][j]表示前i我的中k我的分配到房間號爲j的方法數 (0<=k<=i)
dp[0][0]=0;
最後要分類討論,先計算全部人的和的數組根sum
sum==root(a+b) 表示兩個房間都有人的狀況ans=dp[n][a],若是同時sum==a ,則dp[n][a]中包含了只有a的那種狀況 ans=dp[n][a]-1
sum==a 表示只有a房間有人的狀況
sum==b表示只有b房間有人的狀況
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> using namespace std; #define LL long long #define maxn 100010 #define mod 258280327 int s[maxn],n,a,b; int dp[maxn][10]; int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&a,&b); for(int i=1;i<=n;i++)scanf("%d",&s[i]); memset(dp,0,sizeof(dp)); dp[0][0]=1; int sum=0; for(int i=1;i<=n;i++) { sum=(sum+s[i]-1)%9+1; for(int j=0;j<=9;j++) dp[i][j]=dp[i-1][j]; for(int j=0;j<=9;j++) { int t=(j+s[i]-1)%9+1; dp[i][t]=(dp[i][t]+dp[i-1][j])%mod; } } if(sum!=a && sum!=b && sum!=(a+b-1)%9+1) { puts("0"); continue; } int ans=0; if(sum==(a+b-1)%9+1) { ans+=dp[n][a]; if(sum==a)ans--; } if(sum==a)ans++; if(sum==b)ans++; printf("%d\n",ans); } return 0; }
HDU5384
先給n條詢問,再給m個單詞(模式串),求模式串出現的次數和
ac自動機模板題
#include<string.h> #include<algorithm> #include<iostream> #include<stdio.h> #include<queue> using namespace std; char str[100010][10010]; int num[100010],n,m; struct Trie { int next[10010*50][28],fail[10010*50],end[10010*50]; int root,L; int newnode() { for(int i=0; i<26; i++) { next[L][i]=-1; } end[L++]=-1; return L-1; } void init() { L=0; root=newnode(); } void insert(char *s) { int len=strlen(s); int now=root; for(int i=0; i<len; i++) { if(next[now][s[i]-'a']==-1) { next[now][s[i]-'a']=newnode(); } now=next[now][s[i]-'a']; } if(end[now]==-1)///標記模式串出現的次數 { end[now]=1; } else { end[now]++; } } void build() { queue<int>Q; fail[root]=root; for(int i=0; i<26; i++) { if(next[root][i]==-1) { next[root][i]=root; } else { fail[next[root][i]]=root; Q.push(next[root][i]); } } while(!Q.empty()) { // printf("**\n"); int now=Q.front(); Q.pop(); for(int i=0; i<26; i++) { if(next[now][i]==-1) next[now][i]=next[fail[now]][i]; else { fail[next[now][i]]=next[fail[now]][i]; Q.push(next[now][i]); } } } } void query(char* s) { memset(num,0,sizeof(num)); int len=strlen(s); int now=root; for(int i=0; i<len; i++) { now=next[now][s[i]-'a']; int temp=now; while(temp!=root) { if(end[temp]!=-1)///統計全部模式串出現的次數,num數組在0~m之間定能取到全部end[temp]必不大於m { num[end[temp]]+=end[temp]; } temp=fail[temp]; } } int ans=0; for(int i=0; i<=m; i++) { if(num[i]>0) ans+=num[i]; } printf("%d\n",ans); } } ac; char s[10005]; int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=0; i<n; i++) { scanf("%s",str[i]); } ac.init(); for(int i=0; i<m; i++) { scanf("%s",s); ac.insert(s); } ac.build(); //printf("**\n"); for(int i=0; i<n; i++) { ac.query(str[i]); } } return 0; }
HDU5386
給你一個n*n原始矩陣和結果矩陣,有如下兩種操做,給你m個操做,要求將操做排序,使得原始矩陣轉爲結果矩陣
L x y: for(int i=1;i<=n;i++)color[i][x]=y;
H x y:for(int i=1;i<=n;i++)color[x][i]=y;
結果矩陣確定有一行或者一列數字是相同的,只用從結果矩陣出發,每次將數字相同的一行或者一列查詢對應的操做,而後標記爲-1(-1表示任何顏色均可以),原始矩陣並無什麼卵用。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,m; int s[110][110]; struct node { char op[2]; int x,y; }a[550]; int v[550]; int ans[550]; int ok(int k) { int x=a[k].x; int y=a[k].y; if(a[k].op[0]=='L') { for(int i=1;i<=n;i++) { if(s[i][x]!=-1&&s[i][x]!=y)return 0; } for(int i=1;i<=n;i++)s[i][x]=-1; } else{ for(int i=1;i<=n;i++) { if(s[x][i]!=-1&&s[x][i]!=y)return 0; } for(int i=1;i<=n;i++)s[x][i]=-1; } return 1; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { scanf("%d",&s[i][j]); } } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { scanf("%d",&s[i][j]); } } for(int i=1;i<=m;i++) { scanf("%s%d%d",a[i].op,&a[i].x,&a[i].y); } memset(v,0,sizeof(v)); int k=1; for(int i=1;i<=m;i++) { for(int j=1;j<=m;j++) { if(!v[j]&&ok(j)) { v[j]=1; ans[k++]=j; break; } } } for(int i=m;i>1;i--)printf("%d ",ans[i]); printf("%d\n",ans[1]); } return 0; }
HDU5387
給你一個時間 計算時針和分針的夾角,時針和秒針的夾角,分針和秒針的夾角
所有轉爲秒再通分便可
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> using namespace std; const int fen=12*3600; int hh,mm,ss; int a[4],b[4]; int run(int a,int b) { int ans=abs(a-b); ans%=fen; if(ans>fen/2)ans=fen-ans; return ans; } int gcd(int a,int b) { if(a%b==0)return b; return gcd(b,a%b); } void print(int x) { x*=360; int g=gcd(x,fen); int t1=x/g; int t2=fen/g; if(t2==1)printf("%d",t1); else printf("%d/%d",t1,t2); } int main() { int T; scanf("%d",&T); char str[100]; while(T--) { scanf("%s",str); sscanf(str,"%d:%d:%d",&hh,&mm,&ss); if(hh>=12)hh-=12; a[1]=hh*3600+60*mm+ss; a[2]=12*(60*mm+ss); a[3]=12*60*ss; b[1]=run(a[1],a[2]); b[2]=run(a[1],a[3]); b[3]=run(a[2],a[3]); for(int i=1;i<=3;i++) { print(b[i]); printf(" "); } puts(""); } return 0; }