2018 Multi-University Training Contest 8
1001:HDU6397 Character Encoding
公式题,可以用容斥和隔板法推出来。
#include <iostream> #include <cstdio> #include <cstdlib> using namespace std; const int MAX=3e5+5; const long long mod=998244353; long long fac[MAX],rev[MAX]; long long qp(long long p,long long q) { int cnt=1; while(q>0) { if(q%2==1) cnt=(cnt*p)%mod; q/=2; p=(p*p)%mod; } return cnt%mod; } long long C(long long a,long long b) { if(a<0||b<0) return 0; long long flag=fac[a]; return ((fac[a]*rev[b])%mod*rev[a-b])%mod; } long long n,m,k; long long solve(long long sum,long long num,long long p) { if(sum==0) return 1; long long cnt=0; int i,j; for(i=0;i<=num;i++) { long long a=C(num,i),b=C(sum-p*i-i+num-1,sum-p*i-i); long long flag=(C(num,i)*C(sum-p*i-i+num-1,sum-p*i-i))%mod; if(i%2==1) flag=(mod-flag)%mod; cnt=(cnt+flag)%mod; } return cnt; } int main() { int i,j; int t; scanf("%d",&t); fac[0]=1; rev[0]=1; for(i=1;i<MAX;i++) { fac[i]=(fac[i-1]*i)%mod; rev[i]=qp(fac[i],mod-2); } while(t--){ scanf("%lld%lld%lld",&n,&m,&k); long long ans=solve(k,m,n-1); printf("%lld\n",ans); } return 0; }
1002:HDU6398 Pizza Hub
1004:HDU6340 Parentheses Matrix
构造题,思路被限制了,不应该把所有行或列填满,牺牲两行可以填满更多的列。
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> #include <cmath> #include <vector> #include <iostream> #include <stack> #include <set> #include <map> using namespace std; const int MAX=200+5; int t,n,m; char mp[205][205]; int flag; void solve(){ int i,j; flag=0; if(n%2){ for(i=0;i<n;i++){ for(j=0;j<m/2;j++) mp[i][j]='('; for(j=m/2;j<m;j++) mp[i][j]=')'; } return ; } if(m%2){ for(i=0;i<m;i++){ for(j=0;j<n/2;j++) mp[j][i]='('; for(j=n/2;j<n;j++) mp[j][i]=')'; } return ; } if(n<m){ swap(n,m); flag=1; } if(m>=6){ for(i=1;i<n-1;i++){ mp[i][0]='('; mp[i][m-1]=')'; } for(i=1;i<n-1;i+=2){ for(j=1;j<m-1;j++){ if(j%2==1) mp[i][j]='('; else mp[i][j]=')'; } mp[i][0]='(';mp[i][m-1]=')'; } for(i=2;i<n-1;i+=2){ for(j=1;j<m-1;j++){ if(j%2==0) mp[i][j]='('; else mp[i][j]=')'; } } for(i=0;i<m;i++) mp[0][i]='('; for(i=0;i<m;i++) mp[n-1][i]=')'; return ; } if(m%3==0){ for(i=0;i<n/2;i++){ for(j=0;j<m/6;j++){ mp[i][j*2]='('; mp[i][j*2+1]=')'; } for(j=m/3;j<m*2/3;j++) mp[i][j]='('; for(j=2*m/3;j<m;j++) mp[i][j]=')'; } for(i=n/2;i<n;i++){ for(j=0;j<m/3;j++) mp[i][j]='('; for(j=m/3;j<2*m/3;j++) mp[i][j]=')'; for(j=m/3;j<m/2;j++){ mp[i][j*2]='('; mp[i][j*2+1]=')'; } } } else if((m-4)%3==0){ m-=4; for(i=0;i<n/2;i++){ for(j=0;j<m/6;j++){ mp[i][j*2]='('; mp[i][j*2+1]=')'; } for(j=m/3;j<m*2/3;j++) mp[i][j]='('; for(j=2*m/3;j<m;j++) mp[i][j]=')'; } for(i=n/2;i<n;i++){ for(j=0;j<m/3;j++) mp[i][j]='('; for(j=m/3;j<2*m/3;j++) mp[i][j]=')'; for(j=m/3;j<m/2;j++){ mp[i][j*2]='('; mp[i][j*2+1]=')'; } } m+=4; for(i=0;i<n/2;i++){ mp[i][m-4]='(';mp[i][m-3]='(';mp[i][m-2]=')';mp[i][m-1]=')'; } for(i=n/2;i<n;i++){ mp[i][m-4]='(';mp[i][m-3]=')';mp[i][m-2]='(';mp[i][m-1]=')'; } } else{ m=m-2; for(i=0;i<n/2;i++){ for(j=0;j<m/6;j++){ mp[i][j*2]='('; mp[i][j*2+1]=')'; } for(j=m/3;j<m*2/3;j++) mp[i][j]='('; for(j=2*m/3;j<m;j++) mp[i][j]=')'; } for(i=n/2;i<n;i++){ for(j=0;j<m/3;j++) mp[i][j]='('; for(j=m/3;j<2*m/3;j++) mp[i][j]=')'; for(j=m/3;j<m/2;j++){ mp[i][j*2]='('; mp[i][j*2+1]=')'; } } m=m+2; for(i=0;i<n;i++){ mp[i][m-2]='('; mp[i][m-1]=')'; } } } int main(){ int i,j; scanf("%d",&t); //freopen("1.out","w",stdout); while(t--){ scanf("%d%d",&n,&m); solve(); if(flag){ for(i=0;i<m;i++){ for(j=0;j<n;j++) printf("%c",mp[j][i]); puts(""); } } else{ for(i=0;i<n;i++){ for(j=0;j<m;j++) printf("%c",mp[i][j]); puts(""); } } } return 0; }
1005:HDI6401 Magic Square
简单模拟。
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> #include <cmath> #include <vector> #include <iostream> #include <stack> #include <set> #include <map> using namespace std; const int MAX=10+5; int t,n; char mp[10][10]; void solve(char a,char b){ int x,y; if(a=='1') x=0,y=0; else if(a=='2') x=0,y=1; else if(a=='3') x=1,y=0; else x=1,y=1; if(b=='C'){ char tmp=mp[x][y]; mp[x][y]=mp[x+1][y]; mp[x+1][y]=mp[x+1][y+1]; mp[x+1][y+1]=mp[x][y+1]; mp[x][y+1]=tmp; } else if(b=='R'){ char tmp=mp[x][y]; mp[x][y]=mp[x][y+1]; mp[x][y+1]=mp[x+1][y+1]; mp[x+1][y+1]=mp[x+1][y]; mp[x+1][y]=tmp; } } int main(){ int i; scanf("%d",&t); while(t--){ scanf("%d",&n); for(i=0;i<3;i++) scanf("%s",&mp[i]); for(i=0;i<n;i++){ char s[MAX]; scanf("%s",&s); solve(s[0],s[1]); } for(i=0;i<3;i++) puts(mp[i]); } return 0; }
1009:HUD6405 Make ZYB Happy
找所有本质不同的子串,把所有串建立广义后缀自动机,再把所有串在自动机上跑一边,更新路过的的结点以及parent链,每个节点只能更新一次,最后把所有结点的right集合区间覆盖,再做两遍前缀和可以O(1)回答。
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> #include <cmath> #include <vector> #include <iostream> #include <stack> #include <set> #include <map> #include <string> #define pi acos(-1.0) using namespace std; const int MAX=1e6+5; const int mod=1e9+7; struct suffix_automaton{ string s; int son[MAX][26],pre[MAX],step[MAX],last,total,rt[MAX]; inline void push_back(int v){ step[++total]=v; } void init(){ total=last=0; memset(son,0,sizeof(son)); memset(pre,0,sizeof(pre)); memset(step,0,sizeof(step)); pre[0]=-1; } void Extend(int ch){ push_back(step[last]+1); int p=last,np=total; rt[np]++; for(;!son[p][ch]&&p!=-1;p=pre[p]) son[p][ch]=np; if(p==-1) pre[np]=0; else{ int q=son[p][ch]; if(step[q]!=step[p]+1){ push_back(step[p]+1); int nq=total; memcpy(son[nq],son[q],sizeof(son[q])); pre[nq]=pre[q]; pre[q]=pre[np]=nq; rt[nq]=rt[q]; for(;son[p][ch]==q;p=pre[p]) son[p][ch]=nq; } else pre[np]=q; } last=np; } }suf; long long quickpow(long long x,long long n){ if(n==0) return 1; long long res=quickpow(x*x%mod,n/2); if(n%2) res=res*x%mod; return res; } int n,m,mxlen; string str[MAX]; long long ans[MAX],h[MAX],val[MAX]; int vis[MAX]; long long fac[MAX],inv[MAX],pw; int main(){ int i,j; suf.init(); scanf("%d",&n); for(i=0;i<n;i++) cin>>str[i],mxlen=max(mxlen,(int)str[i].size()); for(i=0;i<n;i++) scanf("%lld",&h[i]); pw=1; for(i=1;i<=mxlen;i++){ pw=pw*26%mod; fac[i]=(fac[i-1]+pw)%mod; inv[i]=quickpow(fac[i],mod-2); } for(i=0;i<n;i++){ //建立广义sam 两种情况 suf.last=0; for(j=0;j<str[i].size();j++){ int np=suf.son[suf.last][str[i][j]-'a']; if(np==0||suf.step[np]!=j+1) suf.Extend(str[i][j]-'a'); else suf.last=np; } } for(i=0;i<n;i++){ int p=0; for(j=0;j<str[i].size();j++){ p=suf.son[p][str[i][j]-'a']; int prep=p; while(prep!=-1){ if(vis[prep]==i+1) break; vis[prep]=i+1; if(!val[prep]) val[prep]=h[i]; else val[prep]=val[prep]*h[i]%mod; prep=suf.pre[prep]; } } } for(i=suf.total;i>=1;i--){ (ans[suf.step[suf.pre[i]]+1]+=val[i])%mod; (ans[suf.step[i]+1]-=val[i])%mod; } for(i=1;i<=mxlen;i++) ans[i]=(ans[i]+ans[i-1]+mod)%mod; for(i=1;i<=mxlen;i++) ans[i]=(ans[i]+ans[i-1]+mod)%mod; scanf("%d",&m); while(m--){ int len; scanf("%d",&len); len=min(len,mxlen); printf("%lld\n",ans[len]*inv[len]%mod); } return 0; }
1010:HDU6406 Taotao Picks Apples
先求出原数列按要求选得到的答案,记录一下每个位置向前最靠近的那个被选的数是哪一个。然后考虑改变某个位置的值时的能产生怎样的贡献。
若它改变后比它之前那个被选的数要大,则它能被加入这个上升子序列;若反之,则不能加入这个上升子序列。故产生贡献的前半部分即它之前的被选的原上升子序列的长度,之后需要得到离它最近的一个比它大的数往后能接多少个,这个能用线段树维护dp出来答案。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<algorithm> 5 6 #define maxn 200000+5 7 #define inf 0x3f3f3f3f 8 9 using namespace std; 10 11 struct Data{ 12 int x,v,pos; 13 bool operator <(const Data &T)const{ 14 return x<T.x; 15 } 16 }q[maxn]; 17 18 struct Seg_Tree { 19 int l, r; 20 int mn; 21 }tr[maxn << 2]; 22 23 int tmp[maxn],h[maxn],ans[maxn],dp[maxn],nlst[maxn],lstsum[maxn]; 24 int n,m,cnt,tot; 25 26 namespace fastIO { 27 #define BUF_SIZE 100000 28 bool IOerror = 0; 29 inline char nc() { 30 static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE; 31 if(p1 == pend) { 32 p1 = buf; 33 pend = buf + fread(buf, 1, BUF_SIZE, stdin); 34 if(pend == p1) { 35 IOerror = 1; 36 return -1; 37 } 38 } 39 return *p1++; 40 } 41 inline bool blank(char ch) { 42 return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; 43 } 44 inline int rd(int &x) { 45 char ch; 46 while(blank(ch = nc())); 47 if(IOerror) return -1; 48 for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0'); 49 return 1; 50 } 51 #undef BUF_SIZE 52 }; 53 using namespace fastIO; 54 55 void Update(int k){ 56 tr[k].mn = min(tr[k << 1].mn, tr[k << 1 | 1].mn); 57 } 58 59 void Build(int k, int l, int r){ 60 tr[k].l = l; tr[k].r = r; 61 if (l == r) { 62 tr[k].mn=inf; 63 return; 64 } 65 int mid = (l + r) >> 1; 66 Build(k << 1, l, mid); 67 Build(k << 1 | 1, mid + 1, r); 68 Update(k); 69 } 70 71 void Insert(int k, int pos, int val){ 72 if (tr[k].l == tr[k].r) { 73 tr[k].mn=val; 74 return; 75 } 76 if (tr[k << 1].r >= pos) Insert(k << 1, pos, val); 77 else if (tr[k << 1 | 1].l <= pos) Insert(k << 1 | 1, pos, val); 78 Update(k); 79 } 80 81 int Query(int k, int l, int r){ 82 if (tr[k].l == l && tr[k].r == r) return tr[k].mn; 83 if (tr[k << 1].r >= r) return Query(k << 1, l, r); 84 else if (tr[k << 1 | 1].l <= l) return Query(k << 1 | 1, l, r); 85 else return min(Query(k << 1, l, tr[k << 1].r) , Query(k << 1 | 1, tr[k << 1 | 1].l, r)); 86 } 87 88 int bsearch(int x){ 89 int l=1,r=tot,res; 90 while(l<=r){ 91 int mid=(l+r)>>1; 92 if(tmp[mid]<=x) res=mid,l=mid+1; 93 else r=mid-1; 94 } 95 return res; 96 } 97 98 int main(){ 99 int T; 100 rd(T); 101 while(T--){ 102 rd(n); rd(m); cnt=tot=0; 103 for(int i=1;i<=n;i++){ 104 rd(h[i]); tmp[++cnt]=h[i]; 105 lstsum[i]=nlst[i]=dp[i]=0; 106 } 107 for(int i=1;i<=m;i++){ 108 rd(q[i].x); rd(q[i].v); q[i].pos=i; 109 tmp[++cnt]=q[i].v; ans[i]=0; 110 } 111 sort(tmp+1,tmp+1+cnt); 112 for(int i=1;i<=cnt;i++) 113 if(tmp[i]!=tmp[i-1]) tmp[++tot]=tmp[i]; 114 for(int i=1;i<=m;i++) q[i].v=bsearch(q[i].v); 115 for(int i=1;i<=n;i++) h[i]=bsearch(h[i]); 116 sort(q+1,q+1+m); 117 Build(1,1,tot+1); 118 for(int i=n;i>=1;i--){ 119 int t=Query(1,h[i]+1,tot+1); 120 dp[i]=(t==inf?1:dp[t]+1); 121 Insert(1,h[i],i); 122 } 123 int now=0; 124 for(int i=1;i<=n;i++){ 125 nlst[i]=now; lstsum[i]=lstsum[i-1]; 126 if(h[now]<h[i]) now=i,lstsum[i]++; 127 } 128 Build(1,1,tot+1); 129 int ii=m; 130 for(int j=n;j>=1;j--){ 131 while(q[ii].x>=j && ii>=1){ 132 if(q[ii].v>h[nlst[q[ii].x]]){ 133 int t=Query(1,q[ii].v+1,tot+1); 134 if(t==inf) ans[q[ii].pos]=lstsum[nlst[q[ii].x]]+1; 135 else ans[q[ii].pos]=lstsum[nlst[q[ii].x]]+1+dp[t]; 136 } 137 else{ 138 int t=Query(1,h[nlst[q[ii].x]]+1,tot+1); 139 if(t==inf) ans[q[ii].pos]=lstsum[nlst[q[ii].x]]; 140 else ans[q[ii].pos]=lstsum[nlst[q[ii].x]]+dp[t]; 141 } 142 ii--; 143 } 144 Insert(1,h[j],j); 145 } 146 for(int i=1;i<=m;i++) 147 printf("%d\n",ans[i]); 148 } 149 return 0; 150 }
1011:HDU6407 Pop the Balloons
1012:HDU6408 From ICPC to ACM
巧妙的贪心。由于零件的储存没有限制,故可以通过以前每天的信息dp出每天最优的零件价格。接着考虑把每天的产能都拉满,对于第i天取出造价最低的demand[i]个电脑卖掉,之后如果超过今天的储存限制,则丢掉造价较高的超出限制的那些电脑。可以通过multiset维护这些信息。
1 #include<set> 2 #include<cstdlib> 3 #include<cstring> 4 #include<cstdio> 5 #include<algorithm> 6 7 #define maxn 50000+5 8 9 using namespace std; 10 11 typedef long long LL; 12 13 struct Data { 14 int sum; LL val; 15 Data() {} 16 Data(int x, LL y) { sum = x; val = y; } 17 bool operator <(const Data &T)const { 18 return val<T.val; 19 } 20 }; 21 22 multiset <Data> s; 23 24 LL sum[maxn], tag; 25 int c[maxn], t[maxn], dem[maxn], m[maxn], p[maxn], cap[maxn], sr[maxn], se[maxn]; 26 int n; 27 28 int main() { 29 int T; 30 scanf("%d", &T); 31 while (T--) { 32 scanf("%d", &n); s.clear(); 33 for (int i = 1; i <= n; i++) 34 scanf("%d%d%d%d", &c[i], &dem[i], &m[i], &p[i]); 35 for (int i = 1; i<n; i++) 36 scanf("%d%d%d", &cap[i], &sr[i], &se[i]); 37 for (int i = 1; i<n; i++) sum[i] = sum[i - 1] + sr[i]; 38 LL tmp = 0x3f3f3f3f; 39 for (int i = 1; i <= n; i++) { 40 t[i] = min((LL)c[i], sum[i - 1] + tmp); 41 tmp = min(tmp, c[i] - sum[i - 1]); 42 } 43 LL tag = 0, ans = 0, all = 0; 44 bool flag = true; 45 for (int i = 1; i <= n; i++) { 46 int now = dem[i]; 47 s.insert(Data ( p[i], m[i] + t[i] - tag )); all += p[i]; 48 while (now && !s.empty()) { 49 set<Data>::iterator it = s.begin(); 50 Data a = (*it); 51 if (a.sum <= now) { 52 now -= a.sum; ans += (LL)a.sum*(a.val + tag); 53 all -= a.sum; s.erase(it); 54 } 55 else { 56 a.sum -= now; ans += (LL)now*(a.val + tag); 57 all -= now; now = 0; s.erase(it); s.insert(a); 58 } 59 } 60 if (now) { 61 flag = false; puts("-1"); 62 break; 63 } 64 while (i!=n && all>cap[i] && !s.empty()) { 65 set<Data>::iterator it = s.end(); 66 Data a = *(--it); 67 if (all - a.sum >= cap[i]) { 68 all -= a.sum; s.erase(it); 69 } 70 else { 71 a.sum -= all - cap[i]; all = cap[i]; 72 s.erase(it); s.insert(a); 73 } 74 } 75 tag += se[i]; 76 } 77 if (flag) printf("%lld\n", ans); 78 } 79 return 0; 80 }