Codeforces 340
A:
询问[l,r]之间有多少个能被x整除的数。
这是简要的题意,分类居然是math。
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4
5 using namespace std;
6
7 int gcd(int a,int b)
8 {
9 if (!b) return a;
10 else return gcd(b,a%b);
11 }
12
13 int main()
14 {
15 int x,y,a,b;
16 scanf("%d%d%d%d",&x,&y,&a,&b);
17 x=x/gcd(x,y)*y;
18 printf("%d\n",b/x-(a-1)/x);
19
20 return 0;
21 }
B:
询问面积最大的四边形。
枚举对角线,两边用叉积找左边和右边最大的三角形。
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<algorithm>
5
6 using namespace std;
7
8 const int maxn=310;
9 const int INF=0x3f3f3f3f;
10
11 int n,x[maxn],y[maxn];
12
13 int cross(int a,int b,int c)
14 {
15 return (x[c]-x[b])*(y[b]-y[a])-(x[b]-x[a])*(y[c]-y[b]);
16 }
17
18 int main()
19 {
20 scanf("%d",&n);
21 for (int a=1;a<=n;a++)
22 scanf("%d%d",&x[a],&y[a]);
23 int ans=0;
24 for (int a=1;a<=n;a++)
25 for (int b=a+1;b<=n;b++)
26 {
27 int maxv=-INF,minv=INF;
28 for (int c=1;c<=n;c++)
29 if (c!=a && c!=b)
30 {
31 int v=cross(a,b,c);
32 maxv=max(maxv,v);
33 minv=min(minv,v);
34 }
35 if (minv<=0 && maxv>=0) ans=max(ans,maxv-minv);
36 }
37 printf("%lf\n",(double)ans/2.0);
38
39 return 0;
40 }
C:
这一场里面最悲哀的是我居然没能顺利的想出这题……唉……
给n个点,每个点需访问一次,问期望走的总长度。
算出每段之间的会被走多少次除以总可能性就行呢,中途可以发现大部分会被直接约掉。
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<algorithm>
5
6 using namespace std;
7
8 const int maxn=100010;
9
10 int n,z[maxn];
11
12 long long gcd(long long a,long long b)
13 {
14 if (!b) return a;
15 else return gcd(b,a%b);
16 }
17
18 int main()
19 {
20 scanf("%d",&n);
21 for (int a=1;a<=n;a++)
22 scanf("%d",&z[a]);
23 sort(z+1,z+n+1);
24 long long ans=(long long)n*z[1];
25 for (int a=1;a<n;a++)
26 ans+=((long long)a*(n-a)*2+(n-a))*(z[a+1]-z[a]);
27 long long x=n;
28 long long g=gcd(ans,x);
29 printf("%I64d %I64d\n",ans/g,x/g);
30
31 return 0;
32 }
D:
题意简化之后就是逆序对之间建立边然后求最大独立集。
那么就是要求一个没有逆序对的最长序列,就是最长上升子序列了。
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<algorithm>
5
6 using namespace std;
7
8 #define lb(x) ((x)&(-(x)))
9
10 const int maxn=100010;
11
12 int n,z[maxn];
13
14 int query(int p)
15 {
16 int ans=0;
17 for (;p;p-=lb(p))
18 ans=max(ans,z[p]);
19 return ans;
20 }
21
22 void modify(int p,int v)
23 {
24 for (;p<=n;p+=lb(p))
25 z[p]=max(z[p],v);
26 }
27
28 int main()
29 {
30 scanf("%d",&n);
31 for (int a=1;a<=n;a++)
32 {
33 int v;
34 scanf("%d",&v);
35 modify(v,query(v)+1);
36 }
37 printf("%d\n",query(n));
38
39 return 0;
40 }
E:
n个数,有些位置是-1,将-1的位置填上数,使得变为一个1-n的排列,且任意ai都不等于i,问方案数。
首先用一个dp做出n个点不存在长度为1的环的方案数,HZC说这是斯特灵数,我只能表示不明觉厉。大概是f[i][j]表示有i个点已加入且有j个长度为1的环,转移就考虑是新增环还是消环即可。
然后再做一次DP,f[i][j]表示已经填了i个数还有j个可能出现重复位置的数,如果剩下的数和j相等了就直接调用上一次做的DP的值,否则考虑选数是选哪一种数即可。
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4
5 using namespace std;
6
7 #define inc(a,b) {a+=b;if (a>=mo) a-=mo;}
8
9 const int maxn=2010;
10 const int mo=1000000007;
11
12 int n,f[maxn][maxn],g[maxn][maxn],h[maxn];
13
14 bool placelose[maxn],show[maxn];
15
16 int main()
17 {
18 scanf("%d",&n);
19 int cnt1=0,cnt2=0;
20 for (int a=1;a<=n;a++)
21 {
22 int v;
23 scanf("%d",&v);
24 if (v==-1) placelose[a]=true,cnt1++;
25 show[v]=true;
26 }
27 for (int a=1;a<=n;a++)
28 if (!show[a] && placelose[a]) cnt2++;
29 g[0][0]=1;
30 for (int a=0;a<cnt2;a++)
31 for (int b=0;b<=cnt2;b++)
32 if (g[a][b])
33 {
34 inc(g[a+1][b+1],g[a][b]);
35 inc(g[a+1][b],(long long)g[a][b]*(a-b)%mo);
36 if (b) inc(g[a+1][b-1],(long long)g[a][b]*b%mo);
37 }
38 for (int a=1;a<=cnt2;a++)
39 h[a]=g[a][0];
40 f[0][cnt2]=1;
41 int ans=0;
42 for (int a=0;a<cnt1;a++)
43 for (int b=0;b<=cnt2;b++)
44 if (f[a][b])
45 {
46 if (cnt1-a==b) inc(ans,(long long)h[b]%mo*f[a][b]%mo)
47 else
48 {
49 inc(f[a+1][b],(long long)f[a][b]*(cnt1-a-b)%mo);
50 inc(f[a+1][b-1],(long long)f[a][b]*b%mo);
51 }
52 }
53 printf("%d\n",(ans+f[cnt1][0])%mo);
54
55 return 0;
56 }