CQOI2015 解题报告

CQOI2015终于全做完了~~~,讲一下题吧

首先这套题比起其他省选还是比较水的,就是5道题比较蛋疼

T1:[CQOI2015]选数

这道题还是比较神的。

首先给个比较神的题解:popoqqq大神的blog这个莫比乌斯反演真的不会

我们记f[i]为gcd=i*k时的个数,可以得到若数都不相等的话,i一定小于1e5(辗转相减法可得),那么当数都不相等时,答案显然为(r/(k*i)-l/(k*i)+1)^n-(r/(k*i)-l/(k*i)+1)-sigma(f[i*j])然后就能愉快的推出来啦,还有就是当l=1时要特判一下

CODE:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 #define mod 1000000007
 7 typedef long long ll;
 8 int power(ll x,ll y) {
 9     ll ans=1;
10     for (;y;y>>=1){
11         if (y&1) (ans*=x)%=mod;
12         (x*=x)%=mod;
13     }
14     return ans;
15 }
16 ll n,l,k,h;
17 #define maxk 100000
18 ll f[maxk+10];
19 int main(){
20     freopen("number.in","r",stdin);
21     freopen("number.out","w",stdout);
22     ll L,H;
23     scanf("%lld%lld%lld%lld",&n,&k,&L,&H);
24     ll l=L/k,h=H/k;
25     if (L%k) l++; 
26     int tmp=0;
27     for (int i=maxk;i;i--) {
28         ll L=l/i,H=h/i;
29         if (l%i) L++;
30         f[i]=(power(H-L+1,n)-(H-L+1)+mod)%mod;
31         for (int j=i+i;j<=maxk;j+=i) f[i]=(f[i]-f[j]+mod)%mod;
32     }
33     if (l==1) f[1]++;
34     printf("%lld
",f[1]);
35     return 0;
36 }
View Code

T2:[CQOI2015]网络吞吐量

这不就是先求出最短路图后拆点跑个最大流么= =。直接做就行了不要考虑时间问题。。。

CODE:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 using namespace std;
 7 typedef long long ll;
 8 #define maxm 150000
 9 #define maxn 1100
10 struct edges{
11     int to,next,dist;ll cap;
12 }edge[maxm*2];
13 int l,next[maxn];
14 inline void _addedge(int x,int y,int z){
15     l++;
16     edge[l*2]=(edges) {x,next[y],z,0};next[y]=l*2;
17     edge[l*2+1]=(edges) {y,next[x],z,0};next[x]=l*2+1;
18 }
19 inline void addedge(int x,int y,ll z){
20     l++;
21     edge[l*2]=(edges){y,next[x],0,z};next[x]=l*2;
22     edge[l*2+1]=(edges){x,next[y],0,0};next[y]=l*2+1;
23 }
24 ll dist[maxn];
25 bool b[maxn];
26 typedef pair<ll,int> ii;
27 priority_queue<ii,vector<ii>,greater<ii> > q;
28 #define fi first
29 #define se second
30 #define inf 0x7fffffff
31 #define Inf inf*1ll*inf
32 int n;
33 inline void dij(){
34     for (int i=1;i<=n;i++) dist[i]=Inf;    
35     dist[1]=0;
36     q.push(ii(0,1));
37     while (!q.empty()){
38         ii u=q.top();q.pop();
39         if (b[u.se]) continue;
40         b[u.se]=1;
41         for (int i=next[u.se];i;i=edge[i].next) 
42             if (dist[u.se]+edge[i].dist<dist[edge[i].to]) {
43                 dist[edge[i].to]=dist[u.se]+edge[i].dist;
44                 q.push(ii(dist[edge[i].to],edge[i].to));
45             }
46     }
47 }
48 int p[maxn],gap[maxn],h[maxn],s,t,N;
49 ll sap(int u,ll flow){
50     if (u==t) return flow;
51     ll cnt=0;
52     for (int i=p[u];i;i=edge[i].next) 
53         if (edge[i].cap&&h[edge[i].to]+1==h[u]) {
54             ll cur=sap(edge[i].to,min(edge[i].cap,flow-cnt));
55             edge[i].cap-=cur;edge[i^1].cap+=cur;
56             p[u]=i;
57             if ((cnt+=cur)==flow) return flow;
58         }
59     if (!(--gap[h[u]])) h[s]=N;
60     gap[++h[u]]++;
61     p[u]=next[u];
62     return cnt;
63 }
64 inline ll maxflow(){
65     for (int i=1;i<=N;i++) p[i]=next[i];
66     ll flow=0;
67     gap[0]=N;
68     while (h[s]<N) flow+=sap(s,Inf);
69     return flow;
70 }
71 int main(){
72     freopen("network.in","r",stdin);
73     freopen("network.out","w",stdout);
74     int m;
75     scanf("%d%d",&n,&m);
76     N=n*2;
77     for (int i=1;i<=m;i++) {
78         int x,y,z;
79         scanf("%d%d%d",&x,&y,&z);
80         _addedge(x,y,z);
81     }
82     dij();
83     memset(next,0,sizeof(next));
84     l=0;
85     for (int i=2;i<=m*2+1;i+=2) {
86         if (dist[edge[i].to]==dist[edge[i^1].to]+edge[i].dist)    
87             addedge(n+edge[i^1].to,edge[i].to,Inf);
88         else if (dist[edge[i^1].to]==dist[edge[i].to]+edge[i^1].dist)    
89             addedge(n+edge[i].to,edge[i^1].to,Inf);
90     }
91     for (int i=1;i<=n;i++) {
92         int x;
93         scanf("%d",&x);
94         addedge(i,n+i,x);
95     }
96     s=1+n,t=n;
97     printf("%lld
",maxflow());
98     return 0;
99 }
View Code

T3:[CQOI2015]任务查询系统

描述:戳我~~~

这道题首先很明显是道裸的数据结构题啦。首先他要求在线,那么按顺序建个函数式线段树就行啦

自己太弱调了好久= =

CODE:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 typedef long long ll;
 8 #define pb push_back
 9 #define maxn 100100
10 struct qnode{
11     int x,y,z;
12 }q[maxn*2];
13 int l;
14 inline void add(int x,int y,int z) {q[++l]=(qnode){x,y,z};}
15 bool cmp(qnode x,qnode y) {return x.x<y.x;}
16 struct node{int lc,rc,sum;ll s;}t[maxn*64];
17 #define mid (l+r>>1)
18 int cnt=0;
19 int ins(int x,int l,int r,int y,int z){
20     int root=++cnt;
21     t[root]=t[x];
22     t[root].s+=y*z;
23     t[root].sum+=z;
24     if (l==r) return root;
25     if (y<=mid) t[root].lc=ins(t[x].lc,l,mid,y,z);
26     else t[root].rc=ins(t[x].rc,mid+1,r,y,z);
27     return root;
28 }
29 ll que(int x,int l,int r,int &k){
30     if (t[x].sum<=k) {
31         k-=t[x].sum;return t[x].s;
32     }
33     if (l==r) {ll ans=l*1ll*k;k=0;return ans;}
34     ll ans=que(t[x].lc,l,mid,k);
35     if (k) ans+=que(t[x].rc,mid+1,r,k);
36     return ans;
37 }
38 vector<int> a;
39 int s[maxn],e[maxn],p[maxn],root[maxn];
40 int main(){
41     int n,m;
42     scanf("%d%d",&n,&m);
43     a.pb(0);
44     for (int i=1;i<=n;i++) {
45         scanf("%d%d%d",s+i,e+i,p+i);
46         e[i]++;
47         a.pb(s[i]);a.pb(e[i]);
48     }
49     sort(a.begin(),a.end());
50     a.resize(unique(a.begin(),a.end())-a.begin());
51     for (int i=1;i<=n;i++) {
52         add(lower_bound(a.begin(),a.end(),s[i])-a.begin(),p[i],1);
53         add(lower_bound(a.begin(),a.end(),e[i])-a.begin(),p[i],-1);
54     }
55     sort(q+1,q+1+l,cmp);
56     #define inf 10000000
57     for (int i=1;i<=l;i++) root[q[i].x]=ins(root[q[i-1].x],1,inf,q[i].y,q[i].z);
58     ll pre=1;
59     for (int i=1;i<=m;i++) {
60         int x,ai,bi,ci;
61         scanf("%d%d%d%d
",&x,&ai,&bi,&ci);
62         int k=1ll+(ai*1ll*(pre%ci)%ci+bi)%ci;
63         pre=que(root[upper_bound(a.begin(),a.end(),x)-a.begin()-1],1,inf,k);
64         printf("%lld
",pre);
65     }
66     return 0;
67 }
View Code

T4:[CQOI2015]多项式

描述:戳我~~~

又是高精度= =

首先我们可以换一下元,吧x-t换成x那就能得到

那么就能算5次即可啦,再考虑怎么快速算组合数

完成啦

CODE:

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<cstring>
  5 #define maxb 4
  6 using namespace std;
  7 char s[10010];
  8 int p[9]={1,10,100,1000,10000,100000,1000000,10000000,100000000};
  9 struct bignum{
 10     int a[10010],n,flag;
 11     bignum(int x){
 12         n=0;memset(a,0,sizeof(a));
 13         flag=x<0?1:0;x=abs(x);
 14         while (x) {a[++n]=x%p[maxb];x/=p[maxb];}
 15         if (!n) n=1;
 16     }
 17     bignum(){n=1;memset(a,0,sizeof(a));flag=0;}
 18     int read(){
 19         scanf("%s",s);
 20         int len=strlen(s);
 21         n=0;
 22         if (len==1&&s[0]=='0') {a[n=1]=0;return 0;}
 23         for (int i=len;i>=1;i-=maxb) {
 24             int t=0;
 25             if (i>maxb) for (int j=i-maxb+1;j<=i;j++) t=t*10+s[j-1]-'0';
 26             else for (int j=1;j<=i;j++) t=t*10+s[j-1]-'0';
 27             a[++n]=t;
 28         } 
 29         return 0;
 30     }
 31     int write(){
 32         if (flag) printf("-");
 33         printf("%d",a[n]);
 34         for (int i=n-1;i>=1;i--) {
 35             for (int j=1;j<maxb;j++) if  (a[i]<p[j]) printf("0"); 
 36             printf("%d",a[i]);
 37         }
 38         printf("
");
 39         return 0;
 40     }
 41     int cmp(bignum x){
 42         if (x.n!=n) return (x.n<n);
 43         for (int i=n;i>=1;i--)
 44             if (x.a[i]!=a[i]) return (x.a[i]<a[i]);
 45         return -1;
 46     }
 47     int div(int x){
 48         int s=0;
 49         for (int i=n;i>=1;i--){
 50             s=a[i]+s*p[maxb];
 51             a[i]=s/x;
 52             s%=x;
 53         }
 54         if (n!=1&&!a[n]) n--;
 55         return s;
 56     }
 57 }a,b;
 58 bignum operator + (bignum x,bignum y){
 59     if (x.flag^y.flag && x.cmp(y)==0)swap(x,y);
 60     if (x.flag==y.flag) {
 61         x.n=max(x.n,y.n);
 62         for (int i=1;i<=x.n;i++) {
 63             x.a[i]+=y.a[i];
 64             x.a[i+1]+=x.a[i]/p[maxb];
 65             x.a[i]%=p[maxb];
 66         }
 67         if (x.a[x.n+1]) x.n++;
 68         return x;
 69     }
 70     for (int i=1;i<=x.n;i++) {
 71         x.a[i]-=y.a[i];
 72         if (x.a[i]<0) {x.a[i]+=p[maxb];x.a[i+1]--;}
 73         while (!x.a[x.n]&&x.n>1) x.n--;
 74     }
 75     return x;
 76 }
 77 bignum operator * (bignum x,bignum y){
 78     bignum ans;
 79     if (x.n==1&&x.a[1]==0) return ans;
 80     if (y.n==1&&y.a[1]==0) return ans;
 81     ans.flag=x.flag^y.flag;
 82     for (int i=1;i<=x.n;i++) 
 83         for (int j=1;j<=y.n;j++) {
 84             ans.a[i+j-1]+=x.a[i]*y.a[j];
 85             ans.a[i+j]+=ans.a[i+j-1]/p[maxb];
 86             ans.a[i+j-1]%=p[maxb];
 87         }
 88     int n=x.n+y.n-1;
 89     while (ans.a[n+1]) {
 90         n++;ans.a[n+1]+=ans.a[n]/p[maxb];
 91         ans.a[n]%=p[maxb];
 92     }
 93     ans.n=n;
 94     return ans;
 95 }
 96 int sum;
 97 int main(){
 98     static bignum n,m;
 99     int t;
100     n.read();
101     scanf("%d",&t);
102     m.read();
103     static int a[4000];
104     a[0]=1;
105     for (int i=1;i<=3389;i++) a[i]=(a[i-1]*1234+5678) % 3389;
106     static bignum tmp=m;
107     int l=tmp.div(3388);
108     static bignum ans,c=bignum(1),T=bignum(1);
109     int cnt=0;
110     for (bignum i=m;i.cmp(n)!=1;i=i+bignum(1),cnt++) {
111         ans=ans+c*T*bignum(a[l]);
112         l=(l+1)%3388;
113         c=c*(i+bignum(1));
114         c.div(cnt+1);
115         T=T*bignum(t);
116     }
117     ans.write();
118     return 0;
119 }
View Code

T5:[CQOI2015]标示设计

描述:戳我~~~

首先我们考虑轮廓线,那么每个L可能有四种状态:已经结束,还未开始,还没拐弯,已经拐弯,那么如果从上到下,从左到右做的话,可以发现最多只有3条横边被标记,那么对每个L我们可以用一维来存这个状态,在加上起始状态还有终止状态就行啦,然后已经拐弯的状态一定是在那条竖边上在讨论下就行啦

由于我是从左到右,从上到下做的,所以每一维就多了1倍的状态,所以在BZ上就光荣的TLE啦,不过在学校的oj上还是能过的。所以代码就不贴啦

原文地址:https://www.cnblogs.com/New-Godess/p/4461428.html