T1:算
等比数列的求和公式求x1 + x2 +…+xm。
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const ll p=1e9+7;
inline int read()
{
int res=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
res=res*10+ch-'0';
ch=getchar();
}
return f*res;
}
inline ll kuaisumi(ll x,ll y)
{
ll sum=1;x=x%p;
while(y)
{
if(y&1) sum=sum*x%p;
x=x*x%p;
y/=2;
}
return sum;
}
int m,n;
ll ans;
int main()
{
freopen("sum.in","r",stdin);
freopen("sum.out","w",stdout);
n=read();m=read();ans=(ll)m;
for(register ll i=2;i<=n;i++)
{
ll x1=kuaisumi(i,m)-1;
ll x2=kuaisumi(i-1,p-2);
ans=(ans%p+i%p*x1%p*x2%p)%p;
}
cout<<ans%p;
fclose(stdin);
fclose(stdout);
return 0;
}
T2:游:
每个景点最少被访问一次,有且仅有一条路径只被访问过一次,其余的访问过2次。
算出所有边的和*2-最长路。
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int maxn=5e4+10;
inline int read()
{
int res=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
res=res*10+ch-'0';
ch=getchar();
}
return res*f;
}
int n,t,sum,maxx;
int head[maxn],nxt[maxn*2],to[maxn*2],w[2*maxn];
int dis[maxn];
bool vis[maxn];
inline void add(int x,int y,int z)
{
t++;nxt[t]=head[x];head[x]=t;to[t]=y;w[t]=-1*z;
}
inline int Max(int x,int y)
{
if(x>y) return y;
else return x;
}
priority_queue<pair<int ,int> >q;
inline void dij()
{
q.push(make_pair(0,1));
while(q.size())
{
int x=q.top().second;q.pop();
if(vis[x]) continue;
vis[x]=1;
for(register int i=head[x];i;i=nxt[i])
{
int y=to[i],z=w[i];
if(vis[y]) continue;
if(dis[y]>dis[x]+z)
{
dis[y]=dis[x]+z;
q.push(make_pair(dis[y],y));
}
}
}
}
int main()
{
freopen("tour.in","r",stdin);
freopen("tour.out","w",stdout);
n=read();
for(register int x,y,z,i=1;i<n;i++)
{
x=read();y=read();z=read();
sum+=z;
add(x,y,z);add(y,x,z);
}
for(register int i=2;i<=n;i++) dis[i]=999999999;
dij();
for(register int i=2;i<=n;i++) maxx=Max(dis[i],maxx);
cout<<sum*2+maxx;
fclose(stdin);
fclose(stdout);
return 0;
}
T3 运:
位数每增加一幸运数的数量扩大一倍,因为ai<=1e9,所以幸运数最多有1022个。
一个k个数组成的不幸运子序列假设有k1个幸运数,k2个不幸运数。
这个不幸运数列的方案是选出k1个幸运数方案数 * 选出k2个不幸运数的方案数。
不幸运数的方案数好求,设不幸运数的总数为m,答案为C(m,k2);
接下来求选出k1个幸运数的方案数。
分别有两个数组a,b存幸运数和此幸运数的数量,dp[i][j]表示只用前i个幸运数组成j个不幸运子序列的方案数,因为是不幸运的,所以每个幸运数最多被用1次。
求出状态转移方程:dp[i][j]=(dp[i-1][j] (不用这个幸运数)+b[i](选出这个幸运数)* dp[i-1][j-1](用这个幸运数))。在清北5上也有一题和此方法类似。
最后dp[1022][j], 就表示用所有幸运数组成长为j的数列的方案数。
枚举每个合法的k1,k2,求和。
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const ll p=1e9+7;
inline ll read()
{
ll res=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
res=res*10+ch-'0';
ch=getchar();
}
return res*f;
}
inline ll kuaisumi(ll x,int y)
{
ll sum=1;
while(y){
if(y&1) sum=sum*x%p;
x=x*x%p;
y/=2;
}
return sum;
}
int f[100100];
inline ll C(ll n,ll k)
{
if(k>n) return 0;
ll n1=f[n],k1=f[k],m1=f[n-k];
ll x1=kuaisumi(m1,p-2)%p;
ll x2=kuaisumi(k1,p-2)%p;
ll x=n1%p*x1%p*x2%p;
return x;
}
inline int judge(ll x)
{
int num=0,wei=1;
while(x)
{
int y=x%10;
if(y!=4&&y!=7) return 0;
if(y==4) num+=1*wei;
if(y==7) num+=2*wei;
wei*=2;
x/=10;
}
return num;
}
int n,k,cnt,ans,m,num;
int dp[1050][1050];
int a[1050];
int b[1050];
int c[1050];
int vis[1050];
int main()
{
freopen("lucky.in","r",stdin);
freopen("lucky.out","w",stdout);
n=read();k=read();
for(register int i=1;i<=n;i++)
{
ll x=read();
int y=judge(x);
if(y!=0)
{
cnt++;
if(!vis[y])
{
num++;
a[num]=y;
vis[y]=num;
b[num]=1;
}
else
b[vis[y]]++;
}
}
dp[0][0]=1;
for (int i=0;i<num;++i)
{
for (int j =0; j<= i; ++j) {
dp[i+1][j] = (dp[i+1][j] + dp[i][j]%p) %p;
dp[i+1][j+1] = (dp[i+1][j+1]%p +(dp[i][j]%p * b[i+1] % p)) %p;
}
}
f[0]=1;
for(int i=1;i<=n;i++)
f[i]=f[i-1]%p*i%p;
m=n-cnt;
int st=max(0,k-cnt);
int ed=min(k,m);
for(int i=st;i<=ed;i++)
{
if(k-i<0) break;
ans=(ans+dp[num][k-i]%p*C(m,i)%p)%p;
}
cout<<ans;
return 0;
}