還沒補完,慢慢補,能寫多少是多少···
2016
題目描述
給出正整數 n 和 m,統計滿足以下條件的正整數對 (a, b) 的數量:
- 1 a n, 1 b m
- a b 是 2016 的倍數。
思路
(a b)% mod = (a%mod b%mod)%mod
所以如果找到一個a%mod == 0,那麼 (n-a)/mod 就是%mod = 0的數量
代碼
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int n,m;
while(cin>>n>>m){
ll ans = 0;
for(int i=1;i<=min(n,2016);++i){
for(int j=1;j<=min(m,2016);++j){
if(i*j%2016 == 0){
ans += 1LL*((n-i)/2016+1)*((m-j)/2016+1);
// 加一是因爲加上本身
}
}
}
cout<<ans<<endl;
}
return 0;
}
有向無環圖
題目描述
Bobo 有一個 n 個點,m 條邊的有向無環圖(即對於任意點 v,不存在從點 v 開始、點 v 結束的路徑)。
爲了方便,點用 1, 2, ,n 編號。
設 表示點 x 到點 y 不同的路徑數量(規定 ),Bobo 想知道
除以 的餘數。
其中,是給定的數列。
思路
因爲只需要知道到所有點的數量和,而不是到定點的數量和。所有利用維護從點到能到達的所有點的數組之和,如果現在有點指向的邊。那麼狀態轉移的式子爲:
然後統計答案就OK了
代碼
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
const int mod = 1e9+7;
vector<int> g[maxn];
int a[maxn],b[maxn];
int in[maxn],dp[maxn];
void init(int n){
memset(in,0,sizeof(in));
memset(dp,0,sizeof(dp));
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i=1;i<=n;++i)
g[i].clear();
}
void Print(int n){
cout<<"dp"<<endl;
for(int i=1;i<=n;++i)
cout<<i<<" "<<dp[i]<<endl;
cout<<endl;
}
int main()
{
//freopen("in.txt","r",stdin);
ios::sync_with_stdio(false);
int n,m,x,y;
while(cin>>n>>m)
{
init(n);
for(int i=1;i<=n;++i)
cin>>a[i]>>b[i];
for(int i=0;i<m;++i){
cin>>x>>y;
g[y].push_back(x);
in[x]++;
}
queue<int> que;
for(int i=1;i<=n;++i)
if(in[i] == 0)
que.push(i);
while(!que.empty()){
int now = que.front();
que.pop();
for(int i=0;i<g[now].size();++i){
int x = g[now][i];
if(x == now)
continue;
dp[x] = (1LL*dp[x] + dp[now])%mod;
dp[x] = (1LL*dp[x] + b[now])%mod;
in[x]--;
if(in[x] == 0)
que.push(x);
}
}
ll ans = 0;
for(int i=1;i<=n;++i)
ans = (ans + (1LL*a[i]*dp[i])%mod)%mod;
cout<<ans<<endl;
//Print(n);
}
return 0;
}
Parenthesis
題目描述
規定一類字符串是平衡的,這類字符串的規定如下:
- 空串S認爲是平衡的
- 如果是平衡的,那麼形如,S也是平衡的
- 如果是平衡的,那麼形如,S也是平衡的
現在給定一個平衡的字符串,有個操作,每一個操作有兩個數字
將原字符串的第與交換,問交換後的字符串是否依然平衡
數據規模爲
思路
首先根據題目容易推出:
- 如果交換的兩個字符相同,不影響字符串的平衡性
- 如果交換的兩個字符在前,在後,也不影響字符串的平衡性
現在需要考慮的就是最後一種情況:如果需要交換的兩個字符在前,在後
很容易想到一個思路:
統計字符串的前綴和,即有一個左括號和加一,一個右括號減一。
在上述說的情況下交換對於前綴和數組的影響就是對於交換座標的左閉右開區間進行區間減法,出現非法的情況就是前綴和中出現負數。
這個時候已經可以直接套一個線段樹的板子,但區間減法的線段樹寫起來有點麻煩,所以還可以再優化。
即直接套一個區間查詢的板子,看區間內有沒有小於2的數。
代碼
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+7;
const int INF = 0x3f3f3f3f;
char str[maxn];
int a[maxn],b[maxn],pre[maxn];
int tree[maxn<<2];
void build(int l,int r,int k){
if(l > r) return ;
if(l == r){
tree[k] = pre[l];
return ;
}
int mid = (l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
tree[k] = min(tree[k<<1],tree[k<<1|1]);
}
int query(int l,int r,int ql,int qr,int k){
if(l>qr || r<ql || l>r)
return INF;
if(l>=ql && r<=qr)
return tree[k];
int mid = (l+r)>>1;
return min(query(l,mid,ql,qr,k<<1),query(mid+1,r,ql,qr,k<<1|1));
}
int main()
{
//freopen("in.txt","r",stdin);
ios::sync_with_stdio(false);
int n,q;
while(cin>>n>>q)
{
memset(pre,0,sizeof(pre));
memset(tree,0,sizeof(tree));
cin>>str+1;
for(int i=0;i<q;++i)
cin>>a[i]>>b[i];
for(int i=1;i<=n;++i){
if(str[i] == '(')
pre[i] = pre[i-1]+1;
else
pre[i] = pre[i-1]-1;
}
build(1,n,1);
for(int i=0;i<q;++i){
if(str[a[i]] == str[b[i]])
cout<<"Yes"<<endl;
else{
if(a[i] > b[i]) swap(a[i],b[i]);
if(str[a[i]] == ')' && str[b[i]] == '(')
cout<<"Yes"<<endl;
else{
int now = query(1,n,a[i],b[i]-1,1);
if(now < 2) cout<<"No"<<endl;
else cout<<"Yes"<<endl;
}
}
}
}
return 0;
}
三角形和矩形
題目描述
obo 有一個三角形和一個矩形,他想求他們交的面積。
具體地,三角形和矩形由 8 個整數 描述。
表示三角形的頂點座標是
矩形的頂點座標是
思路
計算幾何板子題,需要注意不能用cout,不然會WA···
代碼
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-10;
const double PI=acos(-1.0);
struct Point{
double x,y;
Point(double x=0,double y=0):x(x),y(y){}
};
typedef Point Vector;
Vector operator -(Point a,Point b){
return Vector(a.x-b.x,a.y-b.y);
}
Vector operator +(Point a,Point b){
return Vector(a.x+b.x,a.y+b.y);
}
Vector operator *(Vector a,double p){
return Vector(a.x*p,a.y*p);
}
Vector operator /(Vector a,double p){
return Vector(a.x/p,a.y/p);
}
bool operator <(const Point& a,const Point& b){
return a.x<b.x||(a.x==b.x&&a.y<b.y);//在有精度需求,比如使用lower_bound的時候,加上dcmp()
}
int dcmp(double x){
if(fabs(x)<eps)return 0;
if(x<0)return -1;
return 1;
}
bool operator ==(const Point& a,const Point& b){
return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}
double Cross(Vector a,Vector b){
return a.x*b.y-a.y*b.x;
}//叉積
Point GetlineIntersection(Point p,Vector v,Point q,Vector w){
Vector u=p-q;
double t=Cross(w,u)/Cross(v,w);
return p+v*t;
}
typedef vector<Point> Polygon;
//多邊形的有向面積,逆時針爲正
double PolygonArea(Point po[],int n) {
double area = 0.0;
for(int i = 1; i < n-1; i++) {
area += Cross(po[i]-po[0], po[i+1]-po[0]);
}
return area * 0.5;
}
double PolygonArea(Polygon po) {
int n=po.size();
double area = 0.0;
for(int i = 1; i < n-1; i++) {
area += Cross(po[i]-po[0], po[i+1]-po[0]);
}
return area * 0.5;
}
double cross(Point a,Point b,Point c)
{
return Cross(a-c,b-c);
}
double CPIA(Point a[], Point b[], int na, int nb){//傳入兩個三角形,求相交部分的凸包
Point p[20], tmp[20]; //複製點集與臨時點集(P其實可以用B來做
int tn, sflag, eflag; //每輪相交凸包的點,叉乘符號
a[na] = a[0], b[nb] = b[0]; //末點用初點複製方便首末點連邊
memcpy(p,b,sizeof(Point)*(nb + 1)); //把B複製到P
for(int i=0;i<na&&nb>2;i++){ //掃一次A
sflag=dcmp(cross(a[i+1],p[0],a[i])); //取A兩點與B第一點求叉乘符號
for(int j=tn=0;j<nb;j++,sflag=eflag){ //掃一次B,更新TMP,TN是點數
if(sflag>=0)tmp[tn++]=p[j]; //叉乘爲正就是B數組的那個點壓入
eflag=dcmp(cross(a[i+1],p[j+1],a[i]));//求叉乘符號
if((sflag^eflag)==-2)tmp[tn++]=GetlineIntersection(a[i],a[i+1]-a[i],p[j],p[j+1]-p[j]);
//tmp[tn++]=intersection(a[i],a[i+1],p[j],p[j+1]);//求交點
}
memcpy(p, tmp, sizeof(Point) * tn); //把TMP複製到P
nb = tn, p[nb] = p[0];//TN即TMP點數記到NB
}//其實該是NP表示P數組個數,這裏省了個變量就用NB表示,下面第二行做參數而已
if(nb < 3) return 0.0; //相交部分凸包不夠三個點,面積就是0
return PolygonArea(p, nb); //求出相交凸包部分的面積
}
double SPIA(Point a[], Point b[], int na, int nb){//傳入兩個多邊形的點
int i,j; //循環變量
Point t1[4],t2[4]; //其實T13與T23沒用上
double res=0,num1,num2; //答案初始化,及叉乘符號
a[na]=t1[0]=a[0],b[nb]=t2[0]=b[0]; //初始化T1,T2和ANA,BNB
for(i=2;i<na;i++){ //掃一次第一個多邊形全部點
t1[1]=a[i-1],t1[2]=a[i]; //每次在第一個多邊形取兩個點賦給T11,T12
num1=dcmp(cross(t1[1],t1[2],t1[0]));//求出叉乘符號
if(num1<0)swap(t1[1],t1[2]); //小於0則改變T11,T12可使叉乘符號變正,實即改變T1三個點的順逆
for(j=2;j<nb;j++){ //掃一次第二個多邊形全部點
t2[1]=b[j-1],t2[2]=b[j]; //然後再在第二個多邊形取兩個點賦給T21,T22
num2=dcmp(cross(t2[1],t2[2],t2[0]));//求出叉乘符號
if(num2<0)swap(t2[1],t2[2]);//小於0則改變T11,T12可使叉乘符號變正,實即改變T1三個點的順逆
res+=CPIA(t1,t2,3,3)*num1*num2; //累加相交部分面積
}
}
res=fabs(res);
return res;
}
Point a[5],b[5];
int main()
{
//freopen("in.txt","r",stdin);
int x1,x2,x3,x4,y1,y2,y3,y4;
while(scanf("%d %d %d %d",&x1,&y1,&x2,&y2)!=EOF){
scanf("%d %d %d %d",&x3,&y3,&x4,&y4);
a[0].x = x1;a[0].y = y1;
a[1].x = x1;a[1].y = y2;
a[2].x = x2;a[2].y = y1;
b[0].x = x3;b[0].y = y3;
b[1].x = x3;b[1].y = y4;
b[2].x = x4;b[2].y = y4;
b[3].x = x4;b[3].y = y3;
double s1 = SPIA(a,b,3,4);
printf("%.8f\n",fabs(s1));
}
return 0;
}